Кошельки

Слово "кошелек" используется для описания нескольких разных вещей в Ethereum.

На высоком уровне кошелек - это программное приложение, которое служит основным пользовательским интерфейсом Ethereum. Кошелек контролирует доступ к деньгам пользователя, управляет ключами и адресами, отслеживает баланс, а также создает и подписывает транзакции. Кроме того, некоторые кошельки Ethereum могут взаимодействовать с контрактами, такими как токены ERC20.

В более узком смысле, с точки зрения программиста, слово "кошелек" означает систему, используемую для хранения и управления ключами пользователя. В каждом кошельке есть компонент управления ключами. Для некоторых кошельков это все. Другие кошельки являются частью гораздо более широкой категории - браузеров, которые представляют собой интерфейсы для децентрализованных приложений на базе Ethereum, или DApps, которые мы рассмотрим более подробно в [decentralized_applications_chap]. Между различными категориями, которые объединяются под термином "кошелек", нет четких границ.

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

Обзор технологий кошельков

В этом разделе мы обобщим различные технологии, используемые для создания удобных, безопасных и гибких кошельков Ethereum.

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

Распространенное заблуждение об Ethereum заключается в том, что кошельки Ethereum содержат эфир или токены. На самом деле, строго говоря, в кошельке хранятся только ключи. Эфир или другие токены записаны в блокчейне Ethereum. Пользователи управляют токенами в сети, подписывая транзакции с помощью ключей в своих кошельках. В некотором смысле, кошелек Ethereum - это связка ключей. Однако, учитывая, что ключи, хранящиеся в кошельке, - это единственное, что необходимо для передачи эфира или токенов другим пользователям, на практике это различие не имеет особого значения. Где разница действительно имеет значение, так это в изменении своего мышления от централизованной системы обычных банков (где только вы и банк можете видеть деньги на вашем счету, и вам нужно только убедить банк, что вы хотите перевести средства для совершения транзакции) к децентрализованной системе блокчейн-платформ (где каждый может видеть баланс эфира на счете, хотя, вероятно, не знает владельца счета, и каждый должен быть убежден, что владелец хочет перевести средства для совершения транзакции). На практике это означает, что существует независимый способ проверить баланс счета, не нуждаясь в его кошельке. Более того, вы можете перенести операции со своим счетом из текущего кошелька в другой кошелек, если вам разонравится приложение кошелька, которым вы начали пользоваться.

Примечание: Кошельки Ethereum содержат ключи, а не эфир или токены. Кошельки похожи на связки ключей, содержащие пары закрытых и открытых ключей. Пользователи подписывают транзакции закрытыми ключами, доказывая тем самым, что они владеют эфиром. Эфир хранится в блокчейне.

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

Первый тип - недетерминированный кошелек, где каждый ключ генерируется независимо от другого случайного числа. Ключи не связаны друг с другом. Этот тип кошелька также известен как JBOK-кошелек, от фразы "Just a Bunch of Keys".

Второй тип кошелька - это детерминированный кошелек, в котором все ключи получены из одного главного ключа, известного как seed. Все ключи в этом типе кошелька связаны друг с другом и могут быть сгенерированы снова, если у человека есть исходный ключ. Существует несколько различных методов получения ключей, используемых в детерминированных кошельках. Наиболее часто используемый метод деривации использует древовидную структуру, как описано в Иерархические детерминированные кошельки (BIP-32/BIP-44).

Чтобы сделать детерминированные кошельки немного более защищенными от случайных потерь данных, таких как кража телефона или падение его в унитаз, семена часто кодируются в виде списка слов (на английском или другом языке), которые можно записать и использовать в случае аварии. Эти слова известны как мнемонические кодовые слова кошелька. Конечно, если кто-то узнает ваши мнемонические кодовые слова, то он сможет воссоздать ваш кошелек и таким образом получить доступ к эфиру и смарт-контрактам. Поэтому будьте очень, очень осторожны со своим списком слов для восстановления! Никогда не храните его в электронном виде, в файле, на компьютере или телефоне. Запишите его на бумаге и храните в надежном и безопасном месте.

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

Недетерминированные (случайные) кошельки

В первом кошельке Ethereum (выпущенном для предварительной продажи Ethereum) в каждом файле кошелька хранился один случайно сгенерированный закрытый ключ. Такие кошельки заменяются детерминированными кошельками, поскольку кошельки "старого образца" во многих отношениях неполноценны. Например, считается хорошей практикой избегать повторного использования адресов Ethereum в рамках обеспечения максимальной конфиденциальности при использовании Ethereum - то есть использовать новый адрес (для которого нужен новый закрытый ключ) каждый раз, когда вы получаете средства. Вы можете пойти дальше и использовать новый адрес для каждой транзакции, хотя это может оказаться дорогостоящим, если вы имеете дело с большим количеством токенов. Чтобы следовать этой практике, недетерминированный кошелек должен регулярно увеличивать свой список ключей, что означает, что вам нужно будет регулярно делать резервные копии. Если вы когда-нибудь потеряете свои данные (сбой диска, несчастный случай с напитком, кража телефона) до того, как успеете сделать резервную копию кошелька, вы потеряете доступ к своим средствам и смарт-контрактам. С недетерминированными кошельками "типа 0" сложнее всего иметь дело, поскольку они создают новый файл кошелька для каждого нового адреса "точно в срок".

Тем не менее, многие клиенты Ethereum (включая geth) используют файл keystore, который представляет собой файл в кодировке JSON, содержащий один (случайно сгенерированный) закрытый ключ, зашифрованный парольной фразой для дополнительной безопасности. Содержимое JSON-файла выглядит следующим образом:

{
    "address": "001d3f1ef827552ae1114027bd3ecf1f086ba0f9",
    "crypto": {
        "cipher": "aes-128-ctr",
        "ciphertext":
            "233a9f4d236ed0c13394b504b6da5df02587c8bf1ad8946f6f2b58f055507ece",
        "cipherparams": {
            "iv": "d10c6ec5bae81b6cb9144de81037fa15"
        },
        "kdf": "scrypt",
        "kdfparams": {
            "dklen": 32,
            "n": 262144,
            "p": 1,
            "r": 8,
            "salt":
                "99d37a47c7c9429c66976f643f386a61b78b97f3246adca89abe4245d2788407"
        },
        "mac": "594c8df1c8ee0ded8255a50caf07e8c12061fd859f4b7c76ab704b17c957e842"
    },
    "id": "4fcb2ba4-ccdb-424f-89d5-26cce304bf9c",
    "version": 3
}

Формат keystore использует функцию выведения ключа (KDF), также известную как алгоритм растяжения пароля, который защищает от атак методом перебора, по словарю и с использованием радужной таблицы. Проще говоря, закрытый ключ не шифруется непосредственно парольной фразой. Вместо этого парольная фраза растягивается путем многократного хеширования. Функция хеширования повторяется 262 144 раунда, что можно увидеть в JSON хранилища ключей как параметр crypto.kdfparams.n. Злоумышленнику, пытающемуся перебрать ключевую фразу, придется применить 262 144 раунда хеширования для каждой попытки ввода ключевой фразы, что замедляет атаку настолько, что делает ее неосуществимой для ключевых фраз достаточной сложности и длины.

Существует ряд программных библиотек, которые могут читать и записывать формат keystore, например, JavaScript-библиотека keythereum.

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

Детерминированные (посевные) кошельки

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

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

Иерархические детерминированные кошельки (BIP-32/BIP-44)

Детерминированные кошельки были разработаны для того, чтобы упростить получение многих ключей из одного семени. В настоящее время наиболее продвинутой формой детерминированного кошелька является иерархический детерминированный (HD) кошелек, определенный стандартом Биткойна BIP-32. HD-кошельки содержат ключи, выведенные в древовидной структуре, так что родительский ключ может вывести последовательность дочерних ключей, каждый из которых может вывести последовательность внучатых ключей, и так далее. Эта древовидная структура показана на примере кошелька HD: дерево ключей, сгенерированных из одного семени.

HD-кошелек Рисунок 1. HD-кошелек: дерево ключей, сгенерированных из одного семени

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

Второе преимущество HD-кошельков заключается в том, что пользователи могут создавать последовательность открытых ключей, не имея доступа к соответствующим закрытым ключам. Это позволяет использовать HD-кошельки на незащищенном сервере или в режиме "только смотреть" или "только получать", когда кошелек не имеет закрытых ключей, которые могут расходовать средства.

Семена и мнемонические коды (БИП-39)

Существует множество способов кодирования закрытого ключа для безопасного резервного копирования и поиска. В настоящее время предпочтительным методом является использование последовательности слов, которые, будучи собраны вместе в правильном порядке, могут однозначно воссоздать закрытый ключ. Этот метод иногда называют мнемоникой, и он был стандартизирован BIP-39. Сегодня многие кошельки Ethereum (а также кошельки для других криптовалют) используют этот стандарт и могут импортировать и экспортировать семена для резервного копирования и восстановления, используя совместимые мнемоники.

Чтобы понять, почему этот подход стал популярным, давайте рассмотрим пример:

Семя для детерминированного кошелька, в шестнадцатеричном формате FCCF1AB3329FD5DA3DA9577511F8F137 Семя для детерминированного кошелька, из мнемоники из 12 слов

wolf juice proud gown wool unfair
wall cliff insect more detail hub

С практической точки зрения, вероятность ошибки при записи шестнадцатеричной последовательности неприемлемо высока. Напротив, со списком известных слов справиться довольно легко, главным образом потому, что в записи слов (особенно английских) существует высокий уровень избыточности. Если бы "inzect" было записано случайно, то при необходимости восстановления кошелька можно было бы быстро определить, что "inzect" не является допустимым английским словом и что вместо него следует использовать "insect". Мы говорим о записи представления семени, потому что это хорошая практика при управлении HD-кошельками: семя необходимо для восстановления кошелька в случае потери данных (случайно или в результате кражи), поэтому хранение резервной копии очень разумно. Однако семя должно быть исключительно конфиденциальным, поэтому цифровых резервных копий следует тщательно избегать; отсюда и предыдущий совет делать резервные копии с помощью ручки и бумаги.

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

Лучшие практики работы с кошельками

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

  • Мнемонические кодовые слова, основанные на БИП-39
  • HD-кошельки, основанные на BIP-32
  • Многоцелевая структура кошелька HD, основанная на BIP-43
  • Мультивалютные и мультиаккаунтные кошельки, основанные на BIP-44

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

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

Некоторые примеры программных кошельков, поддерживающих эти стандарты, включают (перечислены в алфавитном порядке) Jaxx, MetaMask, MyCrypto и MyEtherWallet (MEW). Примерами аппаратных кошельков, поддерживающих эти стандарты, являются Keepkey, Ledger и Trezor.

В следующих разделах подробно рассматривается каждая из этих технологий.

Совет: Если вы реализуете кошелек Ethereum, он должен быть создан как HD-кошелек, с семенем, закодированным в виде мнемонического кода для резервного копирования, в соответствии со стандартами BIP-32, BIP-39, BIP-43 и BIP-44, как описано в следующих разделах.

Мнемонические кодовые слова (БИП-39)

Мнемонические кодовые слова - это последовательности слов, которые кодируют случайное число, используемое в качестве затравки для создания детерминированного кошелька. Последовательность слов достаточна для воссоздания семени, а затем воссоздания кошелька и всех производных ключей. Приложение для работы с кошельками, реализующее детерминированные кошельки с помощью мнемонических слов, при первом создании кошелька покажет пользователю последовательность из 12-24 слов. Эта последовательность слов является резервной копией кошелька и может быть использована для восстановления и воссоздания всех ключей в том же или любом совместимом приложении кошелька. Как мы объясняли ранее, списки мнемонических слов облегчают пользователям создание резервных копий кошельков, поскольку их легко прочитать и правильно расшифровать.

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

Мнемонические коды определены в BIP-39. Обратите внимание, что BIP-39 - это одна из реализаций стандарта мнемонических кодов. Существует другой стандарт с другим набором слов, используемый кошельком Electrum Bitcoin и предшествующий BIP-39. BIP-39 был предложен компанией, стоящей за аппаратным кошельком Trezor, и несовместим с реализацией Electrum. Однако в настоящее время BIP-39 получил широкую отраслевую поддержку в десятках совместимых реализаций и должен рассматриваться как отраслевой стандарт де-факто. Более того, BIP-39 можно использовать для создания мультивалютных кошельков с поддержкой Ethereum, в то время как семена Electrum не могут этого сделать.

BIP-39 определяет создание мнемонического кода и семян, которые мы описываем здесь в девяти шагах. Для наглядности процесс разделен на две части: шаги с 1 по 6 показаны в разделе Генерация мнемонических слов, а шаги с 7 по 9 - в разделе От мнемоники к семени.

Создание мнемонических слов

Мнемонические слова генерируются кошельком автоматически с использованием стандартизированного процесса, определенного в BIP-39. Кошелек начинает с источника энтропии, добавляет контрольную сумму, а затем сопоставляет энтропию со списком слов:

  1. Создайте криптографически случайную последовательность S длиной от 128 до 256 бит.
  2. Создайте контрольную сумму S, взяв первую длину S ÷ 32 бита из хэша SHA-256 для S.
  3. Добавьте контрольную сумму в конец случайной последовательности S.
  4. Разделите конкатенацию последовательности и контрольной суммы на участки по 11 бит.
  5. Сопоставьте каждое 11-битное значение со словом из предопределенного словаря из 2 048 слов.
  6. Создайте мнемонический код из последовательности слов, сохраняя порядок.

Генерация энтропии и кодирование в виде мнемонических слов показывает, как энтропия используется для генерации мнемонических слов.

Мнемонические коды: энтропия и длина слова показывает взаимосвязь между размером энтропийных данных и длиной мнемонических кодов в словах.

Таблица 1. Мнемонические коды: энтропия и длина слова

128

Энтропия (биты)Контрольная сумма (биты)Энтропия + контрольная сумма (биты)Длина мнемоники (слова)
128413212
160516515
192619818
224723121
256826424

Генерация энтропии и кодирование в виде мнемонических слов Рисунок 2. Генерация энтропии и кодирование в виде мнемонических слов

От мнемоники к семенам

Мнемонические слова представляют собой энтропию длиной от 128 до 256 бит. Энтропия затем используется для получения более длинного (512-битного) семени с помощью функции растяжения ключа PBKDF2. Полученное семя используется для создания детерминированного кошелька и получения ключей.

Функция растягивания ключа принимает два параметра: мнемонику и соль. Назначение соли в функции растяжения ключа заключается в том, чтобы затруднить построение таблицы поиска, позволяющей осуществить атаку "грубой силы". В стандарте BIP-39 соль имеет еще одно назначение: она позволяет ввести ключевую фразу, которая служит дополнительным фактором безопасности, защищающим семя, о чем мы подробнее расскажем в статье Необязательная ключевая фраза в BIP-39.

Процесс, описанный в шагах с 7 по 9, продолжается с процесса, описанного в предыдущем разделе:

  1. Первым параметром функции растяжения ключа PBKDF2 является мнемоника, полученная на шаге 6.
  2. Вторым параметром функции растяжения ключа PBKDF2 является соль. Соль состоит из строковой константы "mnemonic", скомбинированной с необязательной парольной фразой, предоставляемой пользователем.
  3. PBKDF2 растягивает параметры мнемоники и соли с помощью 2 048 раундов хэширования с алгоритмом HMAC-SHA512, получая на выходе 512-битное значение. Это 512-битное значение является затравкой.

От мнемоники к семени показывает, как мнемоника используется для создания семени.

От мнемоники к семенам Рисунок 3. От мнемоники к семенам

Примечание: Функция растяжения ключа с ее 2 048 раундами хэширования является несколько эффективной защитой от атак "грубой силы" на мнемонику или парольную фразу. Она делает дорогостоящим (в вычислениях) перебор более нескольких тысяч комбинаций парольной фразы и мнемоники, в то время как число возможных производных семян огромно (2512, или около 10154) - намного больше, чем число атомов в видимой Вселенной (около 1080).

Таблицы #mnemonic_128_no_pass, #mnemonic_128_w_pass и #mnemonic_256_no_pass показывают некоторые примеры мнемонических кодов и семян, которые они производят.

Таблица 2. 128-битный энтропийный мнемонический код, без парольной фразы, результирующее семя

ЗаголовокЗначение
Входная энтропия (128 бит)0c1e24e5917779d297e14d45f14e1a1a
Мнемоника (12 слов)army van defense carry jealous true garbage claim echo media make crunch
Пассфраза(нет)
Семя (512 бит)5b56c417303faa3fcba7e57400e120a0ca83ec5a4fc9ffba757fbe63fbd77a89a1a3be4c67196f57c39 a88b76373733891bfaba16ed27a813ceed498804c0570

Таблица 3. 128-битный энтропийный мнемонический код, с парольной фразой, результирующим семенем

ЗаголовокЗначение
Входная энтропия (128 бит)0c1e24e5917779d297e14d45f14e1a1a
Мнемоника (12 слов)army van defense carry jealous true garbage claim echo media make crunch
ПассфразаSuperDuperSecret
Семя (512 бит)3b5df16df2157104cfdd22830162a5e170c0161653e3afe6c88defeefb0818c793dbb28ab3ab091897d0 715861dc8a18358f80b79d49acf64142ae57037d1d54

Таблица 4. 256-битный энтропийный мнемонический код, без парольной фразы, результирующее семя

Header1Header2
Входная энтропия (256 бит)2041546864449caff939d32d574753fe684d3c947c3346713dd8423e74abcf8c
Мнемоника (24 слова)cake apple borrow silk endorse fitness top denial coil riot stay wolf luggage oxygen faint major edit measure invite love trap field dilemma oblige
Пассфраза(нет)
Семя (512 бит)3269bce2674acbd188d4f120072b13b088a0ecf87c6e4cae41657a0bb78f5315b33b3a04356e53d062e5 5f1e0deaa082df8d487381379df848a6ad7e98798404

Необязательная парольная фраза в BIP-39

Стандарт BIP-39 допускает использование необязательной парольной фразы при выведении семени. Если парольная фраза не используется, то мнемоника растягивается с солью, состоящей из константной строки "mnemonic", производя конкретное 512-битное семя из любой данной мнемоники. Если используется парольная фраза, функция растяжения производит другое семя из той же мнемоники. Фактически, при использовании одной мнемоники каждая возможная парольная фраза приводит к разным семенам. По сути, не существует "неправильной" парольной фразы. Все парольные фразы действительны, и все они приводят к различным семенам, образуя огромное множество возможных неинициализированных кошельков. Набор возможных кошельков настолько велик (2512), что нет никакой практической возможности перебора или случайного угадывания используемого кошелька, если парольная фраза имеет достаточную сложность и длину.

Совет: В BIP-39 не существует "неправильных" парольных фраз. Каждая парольная фраза ведет к некоторому кошельку, который, если он не использовался ранее, будет пуст.

Необязательная парольная фраза создает две важные возможности:

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

Однако важно отметить, что использование парольной фразы также влечет за собой риск потери:

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

Хотя парольные фразы очень полезны, их следует использовать только в сочетании с тщательно спланированным процессом резервного копирования и восстановления, учитывая возможность того, что наследники, пережившие владельца, смогут восстановить криптовалюту.

Работа с мнемоническими кодами

BIP-39 реализован в виде библиотеки во многих различных языках программирования. Например:

python-mnemonic (https://github.com/trezor/python-mnemonic) Эталонная реализация стандарта командой SatoshiLabs, предложившей BIP-39, на языке Python

ConsenSys/eth-lightwallet (https://github.com/ConsenSys/eth-lightwallet) Легкий JS-кошелек Ethereum для нод и браузера (с BIP-39)

npm/bip39 (https://www.npmjs.com/package/bip39) JavaScript-реализация Bitcoin BIP-39: Мнемонический код для генерации детерминированных ключей

Существует также генератор BIP-39, реализованный в виде отдельной веб-страницы (A BIP-39 generator as a standalone web page), который чрезвычайно полезен для тестирования и экспериментов. Конвертер мнемонических кодов генерирует мнемоники, семена и расширенные закрытые ключи. Его можно использовать в автономном режиме в браузере или получить доступ в режиме онлайн.

Веб-страница генератора БИП-39 Рисунок 4. Генератор БИП-39 в виде отдельной веб-страницы

Создание HD-кошелька из семени

HD-кошельки создаются из одного корневого семени, которое представляет собой 128-, 256- или 512-битное случайное число. Чаще всего это семя генерируется на основе мнемоники, как подробно описано в предыдущем разделе.

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

Кошельки HD (BIP-32) и дорожки (BIP-43/44)

Большинство HD-кошельков используют стандарт BIP-32, который стал фактическим отраслевым стандартом для детерминированной генерации ключей.

Мы не будем обсуждать здесь все детали BIP-32, только компоненты, необходимые для понимания того, как он используется в кошельках. Главный важный аспект - это древовидные иерархические отношения, которые могут иметь производные ключи, как вы можете видеть в кошельке HD: дерево ключей, сгенерированных из одного семени. Также важно понимать идеи расширенных ключей и усиленных ключей, которые объясняются в следующих разделах.

Существуют десятки совместимых реализаций BIP-32, предлагаемых во многих программных библиотеках. В основном они предназначены для кошельков Bitcoin, которые реализуют адреса по-другому, но имеют ту же реализацию деривации ключей, что и BIP-32-совместимые кошельки Ethereum. Используйте библиотеку, разработанную для Ethereum, или адаптируйте ее из Bitcoin, добавив библиотеку кодирования адресов Ethereum.

Существует также генератор BIP-32, реализованный в виде отдельной веб-страницы, которая очень полезна для тестирования и экспериментов с BIP-32.

Предупреждение: Автономный генератор BIP-32 не является HTTPS-сайтом. Это сделано для того, чтобы напомнить вам, что использование этого инструмента небезопасно. Он предназначен только для тестирования. Вы не должны использовать ключи, созданные этим сайтом, с реальными средствами.

Расширенные открытые и закрытые ключи

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

Если ключ является закрытым ключом, он становится расширенным закрытым ключом с префиксом xprv:

xprv9s21ZrQH143K2JF8RafpqtKiTbsbaxEeUaMnNHsm5o6wCW3z8ySyH4UxFVSfZ8n7ESu7fgir8i....

Расширенный открытый ключ отличается префиксом xpub:

xpub661MyMwAqRbcEnKbXcCqD2GT1di5zQxVqoHPAgHNe8dv5JP8gWmDproS6kFHJnLZd23tWevhdn...

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

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

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

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

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

Усиленное извлечение дочерних ключей

Возможность получения ветви открытых ключей из расширенного открытого ключа, или xpub, очень полезна, но она сопряжена с потенциальным риском. Доступ к xpub не дает доступа к дочерним закрытым ключам. Однако, поскольку xpub содержит код цепочки (используемый для получения дочерних открытых ключей из родительского открытого ключа), если дочерний закрытый ключ известен или каким-то образом просочился, он может быть использован вместе с кодом цепочки для получения всех остальных дочерних закрытых ключей. Утечка одного дочернего закрытого ключа вместе с родительским цепным кодом раскрывает все закрытые ключи всех детей. Хуже того, дочерний закрытый ключ вместе с родительским цепным кодом может быть использован для вывода родительского закрытого ключа.

Чтобы противостоять этому риску, кошельки HD используют альтернативную функцию деривации, называемую усиленной деривацией, которая "разрывает" связь между родительским открытым ключом и дочерним цепным кодом. Функция усиленной деривации использует родительский закрытый ключ для получения кода дочерней цепочки, а не родительский открытый ключ. Это создает "брандмауэр" в последовательности родитель/ребенок с цепным кодом, который не может быть использован для компрометации родительского или дочернего закрытого ключа.

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

Индексные номера для нормальной и усиленной деривации

Очевидно, что желательно иметь возможность вывести более одного дочернего ключа из данного родительского ключа. Для этого используется индексный номер. Каждый индексный номер при объединении с родительским ключом с помощью специальной функции деривации дочерних ключей дает отдельный дочерний ключ. Индексный номер, используемый в функции деривации от родителя к ребенку BIP-32, представляет собой 32-битное целое число. Чтобы легко отличить ключи, полученные с помощью обычной (неусиленной) функции деривации, от ключей, полученных с помощью усиленной деривации, этот индексный номер разделен на два диапазона. Индексные номера от 0 до 231-1 (от 0x0 до 0x7FFFFFF) используются только для нормальной деривации. Индексные номера от 231 до 232-1 (от 0x80000000 до 0xFFFFFFFF) используются только для усиленной деривации. Таким образом, если номер индекса меньше 231, ребенок является нормальным, а если номер индекса равен или больше 231, ребенок является усиленным.

Для облегчения чтения и отображения номеров индексов, номера индексов закаленных дочерних ключей отображаются, начиная с нуля, но с простым символом. Поэтому первый обычный дочерний ключ отображается как 0, в то время как первый закаленный дочерний ключ (индекс 0x80000000) отображается как 0'. Последовательно, второй упрочненный ключ будет иметь индекс 0x80000001 и будет отображаться как 1', и так далее. Когда вы видите индекс HD-кошелька i', это означает 231 + i.

Идентификатор ключа кошелька HD (путь)

Ключи в кошельке HD идентифицируются с помощью соглашения об именовании "путь", при этом каждый уровень дерева отделяется символом косой черты (/) (см. примеры путей кошелька HD). Закрытые ключи, производные от главного закрытого ключа, начинаются с m. Открытые ключи, производные от главного открытого ключа, начинаются с M. Поэтому первый дочерний закрытый ключ главного закрытого ключа - m/0. Первый дочерний открытый ключ - M/0. Второй внук первого внука - m/0/1, и так далее.

Родословная" ключа читается справа налево, пока вы не достигнете главного ключа, от которого он был получен. Например, идентификатор m/x/y/z описывает ключ, который является z-м дочерним ключом m/x/y, который является y-м дочерним ключом m/x, который является x-м дочерним ключом m.

Таблица 5. Примеры путей кошелька HD

HD pathKeyописан
m/0Первый (0) дочерний закрытый ключ главного закрытого ключа (m)
m/0/0Закрытый ключ первого внука первого ребенка (m/0)
m/0'/0Первый нормальный внук первого закаленного ребенка (m/0')
m/1/0Закрытый ключ первого внука второго ребенка (m/1)
M/23/17/0/0Открытый ключ первого прапраправнука первого праправнука 18-го внука 24-го ребенка

Навигация по древовидной структуре кошелька HD

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

Два BIP предлагают способ управления этой потенциальной сложностью путем создания стандартов для структуры деревьев кошельков HD. BIP-43 предлагает использовать индекс первой дочерней ветви в качестве специального идентификатора, обозначающего "цель" структуры дерева. Согласно BIP-43, HD-кошелек должен использовать только одну ветвь дерева первого уровня, при этом номер индекса определяет назначение кошелька путем идентификации структуры и пространства имен остальной части дерева. Более конкретно, HD-кошелек, использующий только ветвь m/i'/..., предназначен для обозначения конкретной цели, и эта цель идентифицируется индексным номером i.

Расширяя эту спецификацию, BIP-44 предлагает мультивалютную мультиаккаунтную структуру, обозначаемую установкой номера "цели" в 44'. Все HD-кошельки, следующие структуре BIP-44, идентифицируются по тому, что они используют только одну ветвь дерева: m/44'/*.

BIP-44 определяет структуру как состоящую из пяти предопределенных уровней дерева:

m / purpose' / coin_type' / account' / change / address_index

Первый уровень, purpose', всегда имеет значение 44'. Второй уровень, coin_type', определяет тип криптовалютной монеты, что позволяет создавать мультивалютные HD-кошельки, где каждая валюта имеет свое собственное поддерево на втором уровне. Существует несколько валют, определенных в документе стандартов под названием SLIP0044; например, Ethereum - m/44'/60', Ethereum Classic - m/44'/61', Bitcoin - m/44'/0', а Testnet для всех валют - m/44'/1'.

Третий уровень дерева - account', который позволяет пользователям разделить свои кошельки на отдельные логические субсчета для бухгалтерских или организационных целей. Например, кошелек HD может содержать два "счета" Ethereum: m/44'/60'/0' и m/44'/60'/1'. Каждый счет является корнем своего поддерева.

Поскольку BIP-44 был создан изначально для Биткойна, он содержит "причуду", которая не актуальна в мире Ethereum. На четвертом уровне пути, change, кошелек HD имеет два поддерева: одно для создания адресов получения и одно для создания адресов изменения. В Ethereum используется только путь "получения", поскольку нет необходимости в адресе изменения, как в Bitcoin. Обратите внимание, что если на предыдущих уровнях использовалась усиленная деривация, то на этом уровне используется обычная деривация. Это сделано для того, чтобы позволить уровню счета в дереве экспортировать расширенные открытые ключи для использования в незащищенной среде. Полезные адреса выводятся HD-кошельком как дочерние элементы четвертого уровня, в результате чего пятый уровень дерева становится индексом адреса. Например, третий адрес получения платежей Ethereum на основном счете будет M/44'/60'/0'/0/2. В примере структуры HD-кошелька BIP-44 показано еще несколько примеров.

Таблица 6. Примеры структуры бумажника BIP-44 HD

HD pathKeyописан
M/44'/60'/0'/0/2Третий получаемый открытый ключ для основного счета Ethereum
M/44'/0'/3'/1/1415-й открытый ключ смены адреса для 4-го счета Bitcoin
m/44'/2'/0'/0/1Второй закрытый ключ на основном счете Litecoin для подписания транзакций

Выводы

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