Проверка подписи и шифрование Ethereum ecrecover

Вопрос о подписании и проверке подписей с помощью Solidity был задан в этих вопросах, оба из которых я пытался изучить:

Как я могу подписать часть данных закрытым ключом адреса Ethereum?

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

Тем не менее, есть еще части информации, которые я, кажется, отсутствует.

Прежде всего, я хотел бы начать с вопроса о подписании. В примере строка Schoolbusподписана адресом 0xd1ade25ccd3d550a7eb532ac759cac7be09c2719, а результирующая подпись — 0x2ac19db245478a06032e69cdbd2b54e648b78431d0a47bd1fbab18f79f820ba407466e37adbe9e84541cab97ab7d290f4a64a5825c876d22109f3bf813254e8601.

Все идет нормально. Теперь, что я хотел бы сделать, это проверить с помощью ecrecover, что подпись действительно верна для данного адреса и данных. Дело в том, что ecrecoverпринимает четыре аргумента: ecrecover(h, v, r, s). Помимо hтого, что это хэш и {v, r, s}каким-то образом включает в себя подпись, что именно обозначают v, r и s? И как мне получить все необходимые значения из одной строки 0x2ac19db245478a06032e69cdbd2b54e648b78431d0a47bd1fbab18f79f820ba407466e37adbe9e84541cab97ab7d290f4a64a5825c876d22109f3bf813254e8601?

Что я знаю, так это то, что он ecrecoverвозвращает адрес, а проверка подписи — это, по сути, вопрос сравнения полученного адреса с ожидаемым. Тем не менее, вся процедура кажется излишне сложной.

Помимо этого, мне также было интересно, как я могу создать подпись, подобную этой, 0x2ac19db245478a06032e69cdbd2b54e648b78431d0a47bd1fbab18f79f820ba407466e37adbe9e84541cab97ab7d290f4a64a5825c876d22109f3bf813254e8601или набор с {h, v, r, s}использованием только Solidity, без обхода RPC-JSON, как в случае с вопросом — при условии, что я знаю закрытый ключ?

Посетите ethereum.stackexchange.com/questions/1777/… Здесь я также перечисляю процедуру извлечения r, v и s из строки подписи. Я согласен, что эта процедура слишком сложна, и я выразил эту проблему здесь: github.com/ethereum/EIPs/issues/79
Боюсь, что рассматриваемый вопрос не в Solidity. То, что я пытаюсь выполнить, должно быть выполнено в рамках контракта.
Не могли бы вы немного рассказать о том, почему вы хотели бы подписать что-то внутри контракта? Как уже упоминалось, это откроет закрытый ключ подписавшего для всех.
Я просто хочу проверить подпись в указанном выше формате в контракте. Часть подписания будет предназначена только для модульного тестирования.
Процедура проверки выполняется в договоре о солидности в вопросе, на который я ссылался.
Призыв ecrecoverесть, да. Но у меня нет окружающей среды выполнения на JavaScript, которая могла бы подготовить строку подписи в отдельные компоненты, прежде чем подавать ее в контракт Solidity. Сам контракт должен иметь возможность обрабатывать необработанную строку подписи.
В принципе, я, возможно, просто ищу эквиваленты Solidity web3.toDecimalи String.prototype.slice. Я пробую все ответы в контракте по мере их поступления.
@arik «проверка подписи - это, по сути, вопрос сравнения полученного адреса с ожидаемым» - это не то, что ecrecoverделает. Он сравнивает переданный хэш с хеш-сообщением, расшифрованным из подписи, чтобы убедиться, что они совпадают, а затем возвращает адрес, если он истинен.

Ответы (2)

v, r и s — это параметры, которые можно проанализировать из подписи. Вот хороший пример из библиотеки утилит ethereumjs:

  var sig = secp256k1.sign(msgHash, privateKey)
  var ret = {}
  ret.r = sig.signature.slice(0, 32)
  ret.s = sig.signature.slice(32, 64)
  ret.v = sig.recovery + 27

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

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

r и s вместе со связанным открытым ключом помогают проверить подлинность подписи.

Примечание: я не криптограф. Это то, что я выкопал, пытаясь ответить на те же вопросы, что и у вас. Я бы посоветовал посмотреть некоторые онлайн-ресурсы по эллиптическим кривым.

Aside from this, I was also wondering how I could produce a signature, either like this 0x2ac19db245478a06032e69cdbd2b54e648b78431d0a47bd1fbab18f79f820ba407466e37adbe9e84541cab97ab7d290f4a64a5825c876d22109f3bf813254e8601 or a set of {h, v, r, s} using Solidity alone, without the RPC-JSON detour as is the case in the question – при условии, что я знаю закрытый ключ?

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

Спасибо за ответ! Теперь, если у меня есть только строка подписи, как мне получить из нее объект подписи? recoveryБоюсь, что сама строка подписи не содержит свойства. Кроме того, просто убедитесь: нужен ли хэш для ecrecoversha256?
Можно ли как-то пересчитать v? Боюсь ecrecover, не сработает без передачи правильного значения.
IIUC, когда подпись кодируется DER, сохраняет только точки r и s и отбрасывает «v». Когда я хочу указать значение «v», я просто пробую их оба. Итак, где pubkey_decompressed — это открытый ключ, который создал адрес эфириума: , s)), 'шестнадцатеричный'), если pubkey_decompressed == Possible_pub: вернуть возможное_v
В строку, которая возвращается при использовании eth.sign, включена v. Последние два шестнадцатеричных символа представляют v. Подробнее об этом здесь: ethereum.stackexchange.com/questions/1777/…
для выполнения этого процесса подписания, какой клиент или какая среда мне нужны? " var sig = secp256k1.sign(msgHash, privateKey) var ret = {} ret.r = sig.signature.slice(0, 32) ret.s = sig.signature.slice(32, 64) ret.v = sig .восстановление + 27"

Что именно означают v, r и s?

  • rявляется R.xзначением точки подписи R.
  • sявляется доказательством подписи дляR.x
  • vпараметр восстановления, используемый для облегчения проверки подписи.

vне требуется, но часто включается. Но что v?

Поскольку сигнатура включает только xкоординату точки , на эллиптической кривой Secp256k1 Rесть 0, 1, 2, 3 или 4 совпадающих координаты. yЭти четыре потенциальных кандидата закодированы в нечто, называемое recovery_id.

Идентификатор восстановления может иметь значения в 0..3зависимости от следующих условий:

  • Является R.yчетным и R.xменьше, чем порядок кривой n:recovery_id := 0
  • Является R.y нечетным и R.xменьше порядка кривой n:recovery_id := 1
  • Является R.yчетным и R.x больше , чем порядок кривой n:recovery_id := 2
  • Является R.y нечетным и R.x больше , чем порядок кривой n:recovery_id := 3

Теперь мы знаем, как добраться до идентификатора восстановления. vпросто v = recory_id + 27для биткойнов. В дополнение к vзначениям 27..30, которые отражают только идентификатор восстановления, существует также понятие восстановления сжатых открытых ключей с использованием того же идентификатора восстановления, но с vрасширением v = recovery_id + 31.

Но мы не говорим о Биткойне, так что последнее, но не менее важное, вы хотите взглянуть на EIP-155 , потому что мы больше не используем + 27часть, которую Биткойн использовал для предотвращения защиты от повторного воспроизведения:

v = chain_id * 2 + 35 + recovery_id

В Ethereum vотражает цепочку для защиты от повторного воспроизведения и идентификатор для восстановления подписи.

И как мне получить все необходимые значения из одной строки 0x2ac19db245478a06032e69cdbd2b54e648b78431d0a47bd1fbab18f79f820ba407466e37adbe9e84541cab97ab7d290f4a64a5825c876d22109f3bf813254e8601?

Это просто конкатенированная строка "#{v}#{r}#{s}"с:

  • v = 0x2a
  • r = 0xc19db245478a06032e69cdbd2b54e648b78431d0a47bd1fbab18f79f820ba407
  • s = 0x466e37adbe9e84541cab97ab7d290f4a64a5825c876d22109f3bf813254e8601

Это v42.

chain_id = (v - 35) / 2

Теперь мы можем убедиться, что число v42 действительно только в цепочке с идентификатором 3 (Ropsten).

Что я знаю, так это то, что он ecrecoverвозвращает адрес, а проверка подписи — это, по сути, вопрос сравнения полученного адреса с ожидаемым. Тем не менее, вся процедура кажется излишне сложной.

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

Адрес — это просто красиво отформатированная версия открытого ключа; открытый ключ — это просто точка на эллиптической кривой Secp256k1.

Подпись — это еще один момент. И если вы используете магию открытого ключа и магию подписи, в конце этого сложного математического процесса у вас есть две точки (открытые ключи), и если они полностью совпадают, подпись можно считать проверенной .

Это ecrecoverвозвращает addressпросто для вашего удобства: вы можете напрямую сравнить, совпадает ли адрес подписи с адресом подписавшего — и это намного проще сделать в Solidity, чем иметь дело с несжатыми открытыми ключами.

Я надеюсь, что это проливает свет на этот вопрос.