Как генерируются эфириум-адреса?

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

Насчет дубликата не согласен. Вопрос не в том, чтобы проверить, действителен ли адрес, а в том, как он построен и соответствует ли он формату или является случайным. Ведь это не случайно, а результат каких-то процессов. Тот факт, что в вопросе есть слово «действительный», не является критерием, вы не будете помечать все вопросы со словом «действительный» как дубликаты!
@tayvano не я задал этот вопрос
Совершенно нормально, что вопросы редактируются/улучшаются и проголосовали за повторное открытие. Вот так.
Возможно, стоит сохранить комментарии, указывающие на возможные обманы, поскольку они имеют ценность, предлагая другую точку зрения тем из нас, кто учится.

Ответы (6)

Недавно мое внимание привлекла эта статья, которая намного более глубокая и техническая, чем моя более доступная версия ниже. Он также расскажет вам, как создать его самостоятельно. Я настоятельно рекомендую это: https://kobl.one/blog/create-full-ethereum-keypair-and-address/


Из желтой бумаги

желтая бумага

Есть три основных шага, чтобы получить с частного -> адреса:

  1. Создайте случайный закрытый ключ (64 (шестнадцатеричных) символа / 256 бит / 32 байта)

  2. Получите открытый ключ из этого закрытого ключа (128 (шестнадцатеричных) символов / 512 бит / 64 байта)

  3. Получите адрес из этого открытого ключа. (40 (шестнадцатеричных) символов / 160 бит / 20 байт)

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

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

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

2. Закрытый ключ -> Открытый ключ

Это тяжело и выше моего понимания. Есть что-то с алгоритмом цифровой подписи на эллиптических кривых (ECDSA) и прочим. Но в итоге вы получите открытый ключ размером 64 байта.

3. Открытый ключ -> Адрес

  1. Начните с открытого ключа (128 символов / 64 байта)

  2. Возьмите хэш открытого ключа Keccak-256. Теперь у вас должна быть строка размером 64 символа / 32 байта. (примечание: SHA3-256 со временем стал стандартом, но Ethereum использует Keccak)

  3. Возьмите последние 40 символов/20 байт этого открытого ключа (Keccak-256). Или, другими словами, отбросить первые 24 символа/12 байт. Эти 40 символов / 20 байт и есть адрес. С префиксом 0x он становится длиной 42 символа.

Определения

Адрес: адрес Ethereum представляет учетную запись. Для EOA адрес определяется как последние 20 байтов открытого ключа, управляющего учетной записью, например, `cd2a3d9f938e13cd947ec05abc7fe734df8dd826. Это шестнадцатеричный формат (с основанием 16), который часто указывается явно добавлением 0x к адресу. Web3.js и консольные функции принимают адреса с этим префиксом или без него, но для прозрачности мы поощряем их использование. Поскольку каждый байт адреса представлен двумя шестнадцатеричными символами, адрес с префиксом имеет длину 42 символа. Несколько приложений и API также предназначены для реализации новой адресной схемы с поддержкой контрольной суммы, представленной в кошельке Mist Ethereum с версии 0.5.0. - Документы усадьбы

Закрытый ключ: произвольно выбранное положительное целое число (представленное в виде массива байтов длиной 32 в форме с обратным порядком байтов) в диапазоне [1, secp256k1n − 1]. - Желтая бумага

в чем логика использования только последних 20 байт хеша?
@ k26dr Каждая криптовалюта, кажется, делает что-то подобное, чтобы сохранить уникальные адреса (чтобы вы не отправляли биткойны на адрес ETH и т. д.). Однако я не знаю конкретной причины. Хотя это сделало бы отличный новый вопрос. Вряд ли здесь вы получите реальный ответ.
@ k26dr это просто сделать адреса как можно короче, не рискуя коллизиями.
Хорошая информация. Но не объяснил окончательную (необязательную) контрольную сумму для заглавных букв, как вы сделали здесь. ethereum.stackexchange.com/a/2046/22785 Это также часть генерации общедоступных адресов.
Здесь говорится: ethdocs.org/en/latest/… , что закрытый ключ закодирован с использованием пароля пользователя, похоже, это не упоминается в этом ответе?
@MartinDawson В ответе рассказывается, как генерируются ключи (и это правильно). После создания закрытых/открытых ключей вам необходимо надежно их хранить. Вот для чего нужен зашифрованный паролем файл.
@ k26dr Я подозреваю, что еще одной причиной сокращения адреса до 160 бит было то, что p2p-узлы Kademlia DHT имеют 160-битную спецификацию, и, если я правильно помню, узлы Ethereum должны указывать свой адрес в качестве идентификатора узла Kademlia.
Существует ли официальное * программное обеспечение с открытым исходным кодом для простой генерации закрытых и открытых ключей? (*Сделано ребятами, которые создали ETH)

Пространство для закрытого ключа:

Вот несколько примеров кода, основанных на эллиптической кривой secp256k1, используемой Эфириумом n. быть записано в шестнадцатеричном формате как:0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141

Проверка ошибок:

Различные библиотеки будут выдавать ошибки, если вы попытаетесь ввести в них закрытый ключ, превышающий n, в качестве механизма проверки ошибок (т . Е. Exception: Invalid privkey). См. этот связанный ответ с примерами для более подробной информации.

Связанные параметры кривой:

Мы можем назвать закрытый ключ s, чтобы обозначить его как секретную экспоненту, так как это значение огибает кривую с помощью параметра g(с использованием скалярного умножения), который обозначает общедоступную точку генератора, которая похожа на универсальную константу, которую все знают и используют, чтобы сгенерировать свой открытый ключ из s.

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

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

Вывод криптографически безопасного ключа:

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

Следовательно, секретный показатель должен быть сгенерирован с использованием криптографически безопасного генератора псевдослучайных чисел (CSPRNG), такого как криптографический API консорциума WorldWideWeb (W3C) ( раскрытие информации: я являюсь одним из 12 участников этой спецификации на Github ), так что гораздо менее вероятно, что злоумышленник сможет предсказать это значение, поскольку случайные биты, составляющие это число, поступают из разных мест с вашего локального устройства и из процессов, которые не передают эти данные энтропии онлайн (при условии, что программное обеспечение, которое вы используют безопасно вместе с безопасным CSPRNG).

Пример кода Python:

Используя Python 3, в библиотеке секретов есть CSPRNG, который может быть таким же простым, как запуск следующих команд по порядку из интерпретатора IDLE или файла .py после импорта библиотеки секретов:

secrets.randbits(256)

Приведенная выше команда создаст 256-битное двоичное число, которое можно использовать в качестве закрытого ключа, если оно меньше значения n, но его необходимо отформатировать как байтовый объект в приведенном ниже примере реализации Python с использованием eth-keysбиблиотеки из пакета Репозиторий Ethereum Foundation Github (в приведенном ниже примере может потребоваться установка sha3библиотеки ( pip install pysha3 ), которая содержит Keccak, если ее нет в hashlibбиблиотеке по умолчанию):

import secrets
import sha3
import eth_keys
from eth_keys import keys

private_key = str(hex(secrets.randbits(256))[2:])
private_key_bytes = bytes.fromhex(private_key)
public_key_hex = keys.PrivateKey(private_key_bytes).public_key
public_key_bytes = bytes.fromhex(str(public_key_hex)[2:])
Keccak256_of_public_key_bytes = sha3.keccak_256(public_key_bytes).hexdigest()
public_address = keys.PublicKey(public_key_bytes).to_address()


print('\n Private_key:',private_key,
      '\n Private_key_bytes:',private_key_bytes,
      '\n Public_key_hex:',public_key_hex,
      '\n Public_key_bytes:',public_key_bytes,
      '\n Full_Keccak_digest:',Keccak256_of_public_key_bytes,
      '\n Ethereum address:',public_address)

Пример вывода приведенного выше кода (не для использования в основной сети, например)

 Private_key: 7231bfb75a41481965e391fb6d4406b6c356d20194c5a88935151f05136d2f2e 
 Private_key_bytes: b'r1\xbf\xb7ZAH\x19e\xe3\x91\xfbmD\x06\xb6\xc3V\xd2\x01\x94\xc5\xa8\x895\x15\x1f\x05\x13m/.' 
 Public_key_hex: 0x013e81c4a44c5303b11452f649be9427b75605339d8eba90f8e99cc401a8bd4f7494e0d0740bcc0282af75f9bd4571ed493a05ed02f1b968a45a46f4d77be149 
 Public_key_bytes: b"\x01>\x81\xc4\xa4LS\x03\xb1\x14R\xf6I\xbe\x94'\xb7V\x053\x9d\x8e\xba\x90\xf8\xe9\x9c\xc4\x01\xa8\xbdOt\x94\xe0\xd0t\x0b\xcc\x02\x82\xafu\xf9\xbdEq\xedI:\x05\xed\x02\xf1\xb9h\xa4ZF\xf4\xd7{\xe1I" 
 Full_Keccak_digest: 3f54dd68163875b594cfdc8e8a2250aafb31638b19a83caa49d1ee61089dcb4b 
 Ethereum address: 0x8a2250aafb31638b19a83caa49d1ee61089dcb4b

Шесть шагов от закрытого ключа до адреса Ethereum

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

  1. Сгенерируйте 256-битный безопасный номер в шестнадцатеричном формате, преобразованный в строку с отброшенным префиксом 0x.
  2. Преобразуйте шестнадцатеричную строку, сгенерированную на шаге 1, в объект байтов (b"").
  3. Рассчитайте открытый ключ в шестнадцатеричном формате, используя объект байтов закрытого ключа, созданный на шаге 2.
  4. Преобразуйте шестнадцатеричный открытый ключ, сгенерированный на шаге 3, в байтовый объект.
  5. Вычислите хеш-дайджест объекта bytes, созданного на шаге 4, с помощью Keccak_256.
  6. Возьмите самые правые/последние 40 шестнадцатеричных символов (завершающие 160 бит на стороне с прямым порядком байтов) хеш-дайджеста, созданного на шаге 5, который становится производным адресом эфириума.

Альтернативные зависимости:

В дополнение к библиотеке open-ssl, упомянутой в статье, которую отметил @tayvano, другие библиотеки, которые можно использовать для вычисления общедоступных адресов эллиптических кривых, включают библиотеку ecdsa Python и библиотеку биткойнов secp256k1, написанную на C , хотя последняя будет содержать инструменты для форматирования . биткойн-адреса, которые полностью отличаются от адресов ethereum из-за этапов форматирования и различных алгоритмов хеширования и методов кодирования, даже если базовый закрытый ключ и открытый ключ совпадают, например.

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

Пример : Одним из таких инструментов проверки адреса (контрольной суммы) из библиотеки eth-keys является следующая команда: keys.PublicKey().to_checksum_address()которая использует байты открытого ключа (т. е. передача переменной public_key_bytesв первую скобку будет выглядеть так в приведенной выше программе keys.PublicKey(public_key_bytes).to_checksum_address(), чтобы убедиться, что вычисленный адрес правильный). Вот почему использование существующих библиотек может быть безопаснее, чем писать код с нуля.

PS Ответы и примеры не претендуют на полноту всех рисков/шагов.

В алгоритме генерации ETH HD-Wallet (производство дочернего ключа из пути m/44'/60/0/x) следует использовать «сжатый» или «несжатый» открытый ключ?
Похоже, что используются «сжатые» 33 байта
Ре. комментарий о секретном ключе относительно параметра эллиптической кривой n, см.: eips.ethereum.org/EIPS/eip-1271 : «Если ваша библиотека генерирует податливые подписи, такие как s-значения в верхнем диапазоне, рассчитайте новое s-значение с 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1и перевернуть vс 27на 28или наоборот. Если ваша библиотека также генерирует подписи с помощью 0/ 1for vвместо 27/ 28, добавьте 27, чтобы vтакже принимать эти податливые подписи».

Адреса Ethereum — это хэши открытого ключа. Таким образом, чтобы сгенерировать его, вы должны сначала сгенерировать закрытый ключ (см.: Каков подход к вычислению адреса Ethereum из 256-битного закрытого ключа? ) Закрытый ключ является случайным, но открытый ключ и, следовательно, его хеш, используемый в качестве адреса, не случайно.

Чтобы проверить адрес и, таким образом, узнать его формат, обратитесь к разделу Как проверить, действителен ли адрес Ethereum?

Хорошо! Несколько коротких вопросов: 1) Закрытый и открытый ключи: какой алгоритм шифрования используется? Это то же самое, что и для биткойна? (я думаю, secp256k1 ECDSA) 2) Адрес: это хэш открытого ключа. Какая функция хеширования используется? SHA256?
Да и да, но с keccak256. Но вы должны задать это в другом вопросе и пометить этот вопрос как ответ, если вы считаете, что на первоначальный вопрос дан ответ.
На самом деле я хотел получить ответы на эти вопросы в комментарии (как генерируется адрес, какие алгоритмы и т. д.). Если вы добавите это в ответ, я отмечу его как ответ! Я немного уточню свой первоначальный вопрос.
;) Сначала уточните свой вопрос. Трудно четко ответить на вопросы, которые даже не заданы.
Ссылка только вопросы не приветствуются.
Я думал, что это проблема только для ссылок вне стековых сайтов. Но внутренний должен быть в порядке, так как цель должна быть видна, если видна ссылка. Это проблема только для тех, кто печатает веб-страницы, но никто не должен этого делать.

Если кто-то ищет решение JS:

const Web3 = require('web3')
const web3 = new Web3()
const elliptic = require('elliptic')
const ec = new elliptic.ec('secp256k1')


function pubKeyToAddress(compressedPubkey) {
  let keyPair = ec.keyFromPublic(compressedPubkey, 'hex')
  // remove '04' then add prefix '0x'
  let pubkey = '0x' + keyPair.getPublic(false, 'hex').substr(2)
  let address = trimFirst12Bytes(web3.utils.keccak256(pubkey))
  return web3.utils.toChecksumAddress(address)
}
unction trimFirst12Bytes(hexString) {
  return '0x'.concat(hexString.substr(hexString.length - 40))
}

Вот пакет Python, размещенный в PyPI: eth_address_dump

Дамп eth-адреса из закрытого ключа:

$ echo "0x6ee825aafad19a0d759e1e0ba61d0c523b7b23038998a92d7904458b91667105" | eth_address_dump
private_key = 0x6ee825aafad19a0d759e1e0ba61d0c523b7b23038998a92d7904458b91667105
public_key = 0xaa3e0b3f86053c2aaa08d6f6398e18f76100e0d675680228b000c252e4393e9fe85fc162e43d721533736d79c102139d3035d2d9251ccf809bc5bddb81cc6563
compressed_public_key = 0x03aa3e0b3f86053c2aaa08d6f6398e18f76100e0d675680228b000c252e4393e9f
address = 0xF7dcf60AebA077461862d51b77d6d804C06E0073

Дамп eth-адреса из мнемонических слов:

$ echo "olympic wine chicken argue unaware bundle tunnel grid spider slot spell need" | eth_address_dump
mnemonic = olympic wine chicken argue unaware bundle tunnel grid spider slot spell need
private_key = 0x6ee825aafad19a0d759e1e0ba61d0c523b7b23038998a92d7904458b91667105
public_key = 0xaa3e0b3f86053c2aaa08d6f6398e18f76100e0d675680228b000c252e4393e9fe85fc162e43d721533736d79c102139d3035d2d9251ccf809bc5bddb81cc6563
compressed_public_key = 0x03aa3e0b3f86053c2aaa08d6f6398e18f76100e0d675680228b000c252e4393e9f
address = 0xF7dcf60AebA077461862d51b77d6d804C06E0073

Дамп eth-адреса из сжатого открытого ключа:

$ echo "0x03aa3e0b3f86053c2aaa08d6f6398e18f76100e0d675680228b000c252e4393e9f" | eth_address_dump
public_key = 0xaa3e0b3f86053c2aaa08d6f6398e18f76100e0d675680228b000c252e4393e9fe85fc162e43d721533736d79c102139d3035d2d9251ccf809bc5bddb81cc6563
compressed_public_key = 0x03aa3e0b3f86053c2aaa08d6f6398e18f76100e0d675680228b000c252e4393e9f
address = 0xF7dcf60AebA077461862d51b77d6d804C06E0073
  • Сначала генерируется случайный закрытый ключ из 64 (шестнадцатеричных) символов (256 бит / 32 байта).

  • Затем из сгенерированного закрытого ключа получается открытый ключ из 128 (шестнадцатеричных) символов (512 бит / 64 байта) с использованием алгоритма цифровой подписи на основе эллиптических кривых ( ECDSA ).

  • Затем к открытому ключу применяется хэш-функция Keccak-256 для получения хэш-строки из 64 символов (256 бит / 32 байта). Последние 40 символов этой строки с префиксом 0x становятся окончательным адресом Ethereum. (Примечание: 0x в кодировке означает, что число/строка записаны в шестнадцатеричном формате.)

Источник


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


Пример простого кода Python с использованием модуля eth_account

from eth_account import Account

acc = Account.create(password_string)
prv = acc.key
pub = Account._parsePrivateKey(prv).public_key
addr = acc.address