Как правильно использовать ecrecover для проверки подписи Ethereum?

Я пытался понять, что я делаю неправильно здесь, но мне пока не повезло. Насколько я могу судить, я правильно использую ecrecover, но не могу вернуть адрес подписи Ethereum.

Используя сеанс geth, я создал и подписал хэш, получая значения r, v и s в соответствии с API Javascript :

> var foobar = web3.sha3('foobar')
undefined
> foobar
"38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e"
> var foo = eth.sign('0x803c84d8b64be30554e2edb9c61b50bc78a7231f', foobar).slice(2)
undefined
> var r = foo.slice(0, 64); var s = foo.slice(64, 128); var v = foo.slice(128);
> v
"00"
> r
"723841761d213b60ac1cbf063207cbeba6c2725bcaf7c189e63f13d93fc1dc07"
> s
"789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02"

Затем я перевел эти значения в тест Solidity:

import 'dapple/test.sol';

contract ECRecoverTest is Test {
  function testRecovery() {
    bytes32 foobar = 0x38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e;
    uint8 v = 0x00;
    bytes32 r = 0x723841761d213b60ac1cbf063207cbeba6c2725bcaf7c189e63f13d93fc1dc07;
    bytes32 s = 0x789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02;

    log_address(ecrecover(foobar, v, r, s));
  }
}

Я ожидаю, что мой адрес подписи ( 0x803c84d8b64be30554e2edb9c61b50bc78a7231f) будет зарегистрирован, но все, что я вижу, это:

$ dapple test
Testing...
Using local solc installation...

ECRecoverTest
  test recovery
  LOG:  log_address
  LOG:    val: 0xb62f18e17054f66a817bd4295423adf9ed98873e
  Passed!

Я также попытался преобразовать хэш в ASCII перед его подписанием, а также добавить к шестнадцатеричному префиксу «0x» на тот случай, если проблема была связана с тем, что eth.signфункция не вникала в то, что данные должны обрабатываться как шестнадцатеричное значение.

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

Ответы (2)

Я не уверен, что это ваша единственная проблема, но, по крайней мере, v, который вы получаете, неверен - он должен быть 27 или 28. К сожалению, многие функции подписи не дадут вам его, но вы можете просто попробуйте оба и посмотрите, какой из них дает вам правильный адрес. Не нужно использовать шестнадцатеричный код для «v» — просто введите 27 или 28 как целое число.

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

Здесь есть пример, если это поможет: https://github.com/edmundedgar/realitykeys-examples-ethereum/tree/master/sponsor

Я просто использовал шестнадцатеричный для v здесь для ясности. Хотел продемонстрировать, что это действительно исходило прямо из подписи. Все еще не уверен, в чем проблема, поэтому я обновляю свою копию geth на случай, если мои проблемы связаны с ошибкой в ​​​​старой копии, созданной из Github-commit, которую я запускаю.
Отсутствие «v», вероятно, связано с тем, как это работает — например, стандартная кодировка DER, по-видимому, просто кодирует точки r и s и отбрасывает «v». Как я уже сказал, просто попробуйте их обоих.

Этот смысл является хорошим примером того, как использовать ecrecover. Он использует ассемблер, чтобы отфильтровать r, s, v части подписи и заполнить их ecrecoverфункцией.

assembly {
            r := mload(add(sig, 32))
            s := mload(add(sig, 64))
            // Here we are loading the last 32 bytes, including 31 bytes
            // of 's'. There is no 'mload8' to do this.
            //
            // 'byte' is not working due to the Solidity parser, so lets
            // use the second best option, 'and'
            v := and(mload(add(sig, 65)), 255)
        }

Обратите также внимание на часть v 27, 28, которую упомянул Эдмунд.