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

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

Ответы (1)

Для этого есть Solidity и Serpent ecrecover.

ecrecover(bytes32 data, uint8 v, bytes32 r, bytes32 s) возвращает (адрес)

Аргументы функции:

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

v, r, sэто подпись. ( vэто идентификатор восстановления: 1-байтовое значение, указывающее знак и конечность точки кривой; это значение находится в диапазоне [27, 30], однако протокол Ethereum объявляет две верхние возможности, представляющие бесконечные значения, недействительными)

Важное примечание к приведенным ниже примерам: sha3 — это Keccak-256 .

Вот фрагмент в Solidity :

contract Auth {      
    function verify(address p, bytes32 hash, uint8 v, bytes32 r, bytes32 s) constant returns(bool) {
        // Note: this only verifies that signer is correct.
        // You'll also need to verify that the hash of the data
        // is also correct.
        return ecrecover(hash, v, r, s) == p;
    }
}

Вот пример в Змее :

def test_ecrecover(h, v, r, s):
    return(ecrecover(h, v, r, s))

Соответствующий тестовый код на Python (требуется bitcoinи ethereumупаковывается):

import bitcoin as b
from ethereum import tester, utils


class TestECRecover(object):

    CONTRACT = """
def test_ecrecover(h, v, r, s):
    return(ecrecover(h, v, r, s))
"""

    def setup_class(cls):
        cls.s = tester.state()
        cls.c = cls.s.abi_contract(cls.CONTRACT)
        cls.snapshot = cls.s.snapshot()

    def setup_method(self, method):
        self.s.revert(self.snapshot)

    def test_ecrecover(self):
        priv = b.sha256('some big long brainwallet password')
        pub = b.privtopub(priv)

        msghash = b.sha256('the quick brown fox jumps over the lazy dog')
        V, R, S = b.ecdsa_raw_sign(msghash, priv)
        assert b.ecdsa_raw_verify(msghash, (V, R, S), pub)

        addr = utils.sha3(b.encode_pubkey(pub, 'bin')[1:])[12:]
        assert utils.privtoaddr(priv) == addr

        result = self.c.test_ecrecover(utils.big_endian_to_int(msghash.decode('hex')), V, R, S)
        assert result == utils.big_endian_to_int(addr)

Под капотом ecrecoverиспользуется ECDSARECOVER предварительно скомпилированный контракт , расположенный по адресу 1.


Примечание. Geth и web3.eth.sign добавят к dataсообщению префикс перед подписью.

Метод sign вычисляет специфичную для Ethereum подпись с помощью: sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))).

Добавление префикса к сообщению делает рассчитанную подпись распознаваемой как подпись, специфичная для Ethereum. Это предотвращает неправомерное использование, когда вредоносное DApp может подписывать произвольные данные (например, транзакцию) и использовать подпись, чтобы выдать себя за жертву.

В этом случае второй аргумент to verify()должен быть keccak256("\x19Ethereum Signed Message:\n", len(message), message)вместо keccak256(message).

Связано: ecrecover от Geth и web3.eth.sign

Хотя это уже очень подробный ответ, можете ли вы добавить, что возвращает ecrecover в случае хорошей или недействительной подписи?
Насколько я понимаю, хорошая подпись вернет адрес, с которого была подписана. Плохая подпись вернет другой адрес. Невозможно определить, действительна ли подпись или нет, не зная адреса, по которому должна была выполняться подпись.
Из документов Solidity на ecrecover: «восстановить адрес, связанный с открытым ключом, из подписи эллиптической кривой или вернуть ноль в случае ошибки»
Спасибо анонимному редактору, который добавил важный комментарий к коду: «Вам также необходимо убедиться, что хэш данных также верен».
Если подпись неверна, вы все равно получите действительный адрес. Итак, вам просто нужно заставить подписавшегося включить адрес где-нибудь в исходное сообщение, чтобы проверить его правильность?
Или, наоборот, @sudo, если хэш неверен, вы все равно получите действительный, но неправильный адрес.