31

If I have a cryptographic signature from an Ethereum address key pair, how can I verify that signature?

1 Answer 1

33

Solidity and Serpent have ecrecover for this purpose.

ecrecover(bytes32 data, uint8 v, bytes32 r, bytes32 s) returns (address)

The function arguments are:

data is what was signed. Since it is 32 bytes, that usually means that the initial data is hashed first to 32 bytes, before it was signed.

v, r, s is the signature. (v is the recovery id: a 1 byte value specifying the sign and finiteness of the curve point; this value is in the range of [27, 30], however the Ethereum protocol declares the upper two possibilities, representing infinite values, invalid)

Important note with the examples below, sha3 is Keccak-256.

Here is a snippet in 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;
    }
}

Here is an example in Serpent:

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

The corresponding test code in Python (requires bitcoin and ethereum packages):

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)

Under the hood, ecrecover uses the ECDSARECOVER precompiled contract located at address 1.


Note: Geth and web3.eth.sign will add a prefix to the data message before signing.

The sign method calculates an Ethereum specific signature with: sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))).

By adding a prefix to the message makes the calculated signature recognisable as an Ethereum specific signature. This prevents misuse where a malicious DApp can sign arbitrary data (e.g. transaction) and use the signature to impersonate the victim.

For this case, the second argument to verify() must be keccak256("\x19Ethereum Signed Message:\n", len(message), message) instead of keccak256(message).

Related: ecrecover from Geth and web3.eth.sign

6
  • While already a very thorough answer, can you add what ecrecover returns in case of a good or invalid signature?
    – J-B
    Commented Jan 28, 2016 at 3:32
  • 1
    As I understand it, a good signature will return the address which did the signing. A bad signature will return a different address. There's no way to tell if a signature is valid or not without also knowing the address which was supposed to do the signing.
    – ryepdx
    Commented Mar 20, 2016 at 22:17
  • 1
    From the solidity docs on ecrecover: "recover the address associated with the public key from elliptic curve signature or return zero on error"
    – ZMitton
    Commented Feb 21, 2017 at 22:00
  • Thank you to the anonymous editor who added the important code comment: "You'll also need to verify that the hash of the data is also correct"
    – eth
    Commented Aug 10, 2017 at 6:45
  • If the signature is wrong, you still get a valid address from this. So do you just have to make the signer include the address somewhere in the original message to check for correctness?
    – sudo
    Commented Jun 3, 2018 at 4:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.