Каков подход к вычислению адреса Ethereum из 256-битного закрытого ключа?

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

Написал оболочку вокруг Keccak , чтобы принимать как шестнадцатеричные, так и ASCII-входы для хеширования sha3-224, sha3-256, sha3-384 или sha3-512. Хэши соответствуют тестовым векторам . Хотел бы применить его с помощью команд bitcoin-explorer ( bx ) версии 3 , чтобы посмотреть, смогу ли я синтезировать адреса ETH. Если мне удастся синтезировать адреса для альткойнов ETH, XMR и MAX, я отправлю запрос на включение, чтобы добавить возможности хеширования sha3 в версию bx3, и обновлю эту вики , касающуюся применения bx к альткойнам.

Чтобы вычислить публичный адрес, используя возможности bx secp256k1 , достаточно просто % echo fc8fba997174132184998ab82b28e441e80c73236ccaf8b6a1efadc33febecfc | bx ec-to-public -u :
У меня проблема с Keccak sha3-256. Удаление 04 из указанного выше адреса в sha3-256 и перенос младших 20 байтов вправо не работает.
% ./keccak -x -256 cf90dc2b34937fff7cf1eb4b260f1e5610231134b864761e508505938bbef8fc00aeb265797336b74146e018da7b78070f1f1072540a2c3fe83637ca5d605b3cb992c6ced76bf40cfe875feb 99d0dfbbb6eb831dc0605a82d084e5d930bc6631
Как тогда гарантируется уникальность адресов в сети? Что, если я случайно сгенерировал тот же закрытый ключ, что и кто-то другой, тогда у меня будет тот же адрес? Или, что более вероятно, что, если мой закрытый ключ отличается от чьего-то другого, но сопоставляется с тем же адресом?
Q1) Нет никакой гарантии, что два разных закрытых ключа не могут иметь один и тот же публичный адрес ETH, просто очень маловероятно. Q2) Если есть коллизия между закрытыми ключами, тот, кто тратит первым, получает добычу за счет потери другого. Скорее всего, вы потеряете свои средства в банке по какой-либо причине...

Ответы (3)

  1. Начните с байтов открытого ключа (строка байтов длиной 64)
  2. Из этого открытого ключа возьмите хэш Keccak-256, который повсеместно используется Ethereum (убедитесь, что вы поняли его правильно, так как окончательно стандартизированный хэш SHA3-256 отличается). Теперь у вас должна быть строка байтов длиной 32.
  3. Отбросьте первые 12 байт. Теперь у вас должна быть строка байтов длиной 20, адрес Ethereum, связанный с вашим открытым ключом.

Обновление: Ой! Я вижу, вы хотите это от закрытого ключа, а не от открытого ключа. Это сложнее. Вы должны сначала получить открытый ключ из закрытого ключа, что лучше всего сделать с помощью криптобиблиотеки EC. Я могу показать вам пример кода на Scala, но EC-математика для меня в основном черный ящик. Во-первых, интерпретируйте 256-битный закрытый ключ как большое целое число без знака. Затем см., например, здесь . Curveпредставляет названную эллиптическую кривую secp256k1. Детали математики, увы, мне не под силу, но надеюсь, в какой бы среде вы ни программировали, у вас есть доступ к высококачественной криптобиблиотеке.

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

(извините! мой первоначальный ответ неправильно истолковал сообщение как начало с открытого ключа. Я добавил обновление с несовершенными подсказками по получению открытого ключа из закрытого ключа.)
Я очень запутался, согласно ETHEREUM: БЕЗОПАСНАЯ ДЕЦЕНТРАЛИЗОВАННАЯ ОБОБЩЕННАЯ РЕГИСТРАЦИЯ ТРАНЗАКЦИЙ Я могу отформатировать текст на пишущей машинке, например, хэш-функция Keccak-256 (согласно победившей записи в конкурсе SHA-3) обозначается KEC (и обычно упоминается как как обычный Кекчак). FIPS202_SHA3_256 означает Keccak(1088, 512, input, inputByteLen, 0x06, output, 32). Каковы параметры Keccak для Keccak-256?
Запрос комментариев/мнений почти не упоминает sha3.
Вместо адресов, являющихся хэшем RIPEMD160 хэша SHA256 открытого ключа с префиксом 04, адреса представляют собой просто последние 20 байтов хэша SHA3 открытого ключа.
Итак, это некрасиво. Но стратегия заполнения Keccak изменилась, поскольку функция прошла через процесс стандартизации SHA3. Соответствующее изменение, я думаю, происходит в версии 3.0 здесь , особенно см. padding.h и padding.cpp .
Особенно сравните OldDiversifiedKeccakPaddingи MultiRatePadding. Ethereum использует старую стратегию. Я думаю (но не уверен!) для параметра диверсификатора установлено значение по умолчанию 0. На практике простой способ решить это - сравнить хэш пустой строки. Окончательно стандартизированный SHA3-256 хэширует пустую строку в a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a. Вариант Ethereum использует хэши той же строки, что и c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470.
Погуглите эти два хэша, и вы найдете больше обсуждений. Например, пакет js-sha3 узла может вычислять оба варианта, описывая окончательно стандартизированную версию как , sha3_256а старую версию как keccak_256. Возможно, это неправильное название, поскольку сам Keccak был обновлен, но соглашение об именах кажется обычным. Вам нужно будет найти библиотеку, подходящую для ваших целей, которая делает доступным соответствующий, более старый вариант хэша.
Протестированы хаки KeccakTools , чтобы подтвердить, что [раскомментирование] ( github.com/gvanas/KeccakTools/blob/… ) и закомментирование всего [genKATShortMsg.cpp] ( github.com/gvanas/KeccakTools/blob/master/Sources/… и добавление genShortMsg(1088, 512, 256, "keccak-256", true); // keccak-256, NOT FIPS202_SHA3_256будет воспроизводить хэши, используемые для синтеза адресов Ethereum.Короче говоря, адреса ETH НЕ ВЫЧИСЛЯЮТСЯ с использованием разновидностей Keccak NIST.
@ Стив Уолдман, твои инстинкты не подвели :-)
@skaht не инстинкт! Я ударился об него головой, как и ты. ;)
Я ошибся в том, какая версия Keccak используется Eth 1.0. Это v3, а не что-то более раннее. Эрик Маккарти из Kestrel Institute выследил и тщательно проверил, какая именно версия Keccak Eth используется. Это Версия 3 от 14 января 2011 года . Благодаря работе Маккарти, Ethereum Yellow Paper была обновлена , чтобы точно отразить, какая версия хэша Keccak используется, что является запоздалым улучшением.

Для вычисления адресов ETH используются последние 20 байт хэша Keccak-256. Не следует использовать разновидности Keccak NIST FIPS 202, такие как KeccakCodePackage .

Однако взлом main.c и genKATShortMsg.cpp с помощью KeccakTools даст правильные адреса ETH, подробно описанные в комментарии выше.

Для следующего закрытого ключа ETH: b205a1e03ddf50247d8483435cd91f9c732bad281ad420061ab4310c33166276. Связанный открытый ключ является результатом использования bx.

% echo b205a1e03ddf50247d8483435cd91f9c732bad281ad420061ab4310c33166276 | bx ec-to-public -u
04**6cb84859e85b1d9a27e060fdede38bb818c93850fb6e42d9c7e4bd879f8b9153fd94ed48e1f63312dce58f4d778ff45a2e5abb08a39c1bc0241139f5e54de7df**

Следующий KeccakTools/Example\ trailsфайл конфигурации необходим для выполнения
../bin/KeccakToolsиз Example\ trailsкаталога.

% cat ShortMsgKAT.txt

\# Algorithm Name: NOT_FIPS202_SHA3_256
\# Principal Submitter: SKAHT
Len = 512
Msg = 6cb84859e85b1d9a27e060fdede38bb818c93850fb6e42d9c7e4bd879f8b9153fd94ed48e1f63312dce58f4d778ff45a2e5abb08a39c1bc0241139f5e54de7df

Файл с именем ShortMsgKAT_keccak-256.txtсоздается из выполнения, KeccakToolsкоторый будет содержать:

MD = 787EC5A5313A976F7BDF9EED**AFDEFC1937AE294C3BD55386A8B9775539D81653** 

когда задокументированный выше взлом выполняется для сборки KeccakTools .

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

Отвечая на главный вопрос заголовка о 256-битных закрытых ключах и заголовке:

«Для данного закрытого ключа, сгенерированного MyEtherWallet, я хотел бы видеть, что у меня есть инструменты для независимого получения аналогичных результатов».

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

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

Хотя сама кривая равна конечному полю p, равному: ((((((((2**256)-2**32)-2**9)-2**8)-2**7)-2**6)-2**4)-1)и которое в шестнадцатеричном формате равно: '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f'и имеет длину 256 двоичных битов, закрытый ключ не может быть больше, чем порядок, nкоторый немного меньше, даже если он также 256-битный:'0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141'

То есть закрытый ключ не может быть больше, чемn по параметрам кривой secp256k1 .

После выполнения этой проверки, чтобы убедиться, что ключ действителен, следующими шагами будет использование чего-то вроде библиотеки ECDSA вместе с библиотекой eth-keys в Python.

Ниже приведен пример такой программы на Python, которая принимает закрытый ключ или может генерировать ключи случайным образом (см. комментарий в коде после # for private_key_hex=hex(int(bin(secrets.randbits(256)),base=2))):

import secrets
import math
import sha3
import ecdsa
from ecdsa import SigningKey, SECP256k1
from eth_keys import keys 

private_key_hex=hex(int(input('paste a 0x-padded 64 character hex string, total 66 with 0x'),base=16))
scep256k1_curvelimit= int(0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141) #Curve limit is 
if int(private_key_hex,base=16) > scep256k1_curvelimit:
    print('private key is out of the range of the curve and invalid, do not use!')
else:
    print('private key is within range of curve')

#private_key_hex=hex(int(bin(secrets.randbits(256)),base=2)) Uncomment this to use RANDOM
private_key_hex_nopad=private_key_hex[2:]
private_key=bytearray.fromhex(private_key_hex_nopad)

def address_formatted(to_hash_str): 
    keccak = sha3.keccak_256()
    out = ''
    str_hash = to_hash_str.lower().replace('0x', '')
    keccak.update(str_hash.encode('ascii'))
    create_hash_digit = keccak.hexdigest()

    for i, c in enumerate(str_hash):
        if int(create_hash_digit[i], 16) >= 8:
            out += c.upper()
        else:
            out += c
    return '0x' + out        

keccak = sha3.keccak_256()
f=private_key
private_key = ecdsa.SigningKey.from_string(f, curve=ecdsa.SECP256k1)
public_key = private_key.get_verifying_key().to_string()
keccak.update(public_key)
print(public_key)
address = keccak.hexdigest()[24:]
address_full = keccak.hexdigest()

print("Private key:", private_key.to_string().hex())
print("Public key: ", public_key.hex())
print("Ethereum Address, based on last 40 hex of Keccak Hash digest:    ", address_formatted(address))
print('Full Hash Digest (address is last 40 characters): ',address_full,)

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

scep256k1_curvelimit= int(0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141) #Curve limit is 
if int(private_key_hex,base=16) > scep256k1_curvelimit:
    print('private key is out of the range of the curve and invalid, do not use!')
else:
    print('private key is within range of curve')

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

b'\xa2%\xbfV_\xf4\xea\x03\x9b\xcc\xba>&En\x91\x0c\xd7NF\x16\xd6~\xe0\xa1f\xe2m\xa6\xe5\xe5Z\x08\xd0\xfa\x16Y\xb4\xb5G\xbaq9\xcaS\x1fb\x90{\x9c.r\xb8\x07\x12\xf1\xc8\x1e\xceC\xc3?K\x8b'
Private key: c2c72dfbff11dfb4e9d5b0a20c620c58b15bb7552753601f043db91331b0db15
Public key:  a225bf565ff4ea039bccba3e26456e910cd74e4616d67ee0a166e26da6e5e55a08d0fa1659b4b547ba7139ca531f62907b9c2e72b80712f1c81ece43c33f4b8b
Ethereum Address, based on last 40 hex of Keccak Hash digest:     0x6eA27154616a29708dce7650b475Dd6b82eBa6a3
Full Hash Digest (address is last 40 characters):  f616607efea8e1a5c2f0f8576ea27154616a29708dce7650b475dd6b82eba6a3

Примечание : Keccak также можно получить как часть библиотеки Hashlib или установить из библиотеки pysha3 , в зависимости от установленной версии Python.