How to verify a signature in a smart contract in Solidity

We are going to learn how to verify signatures in a Solidity smart contract and learn how to get the address that generated the signature.

In this tutorial, we are going to learn how to verify signatures in a Solidity smart contract. We are going to see how to get the address that generated the signature.

Ethereum wallets can sign data (a string) off-chain using their private key which generates a unique hash. Then, we can verify that the signature was generated with a specific wallet.

To verify a signature, you need to have the data (the string) that was signed by the signer.

That method is used to ensure that someone has access to a wallet and is not pretending to be someone else.

To learn more about that, you can take a look at our tutorial on how to create a system for your users to sign in with Ethereum wallets.

You can also check out our tutorial on how to request a signature using the user's wallet in JavaScript using Web3.js.

To verify signatures, you need to split them into chunks of specific sizes because the Solidity function that verifies the signatures expects the signature to split into 3 parts with specific byte size.

To do that, you need to split the signature into 3 parts that way:

  • r is the first 66 characters – from 0 to 65 included
  • s is the next 64 characters – from 66 to 129 included – prefixed by 0x
  • v is the last to characters – from 130 to 132 included – as an integer

You can split the signature in Solidity but it's easier and cheaper to do it off-chain.

So in JavaScript, you would split it using this code:

const signature = "0x........." // your signature (132 characters long)

const r = signature.slice(0, 66);
const s = "0x" + signature.slice(66, 130);
const v = parseInt(signature.slice(130, 132), 16);

And is how to verify signatures within smart contracts in Solidity:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

contract Verifier {

    function verify(bytes32 _data, uint8 _v, bytes32 _r, bytes32 _s) public pure returns (address) {
        bytes memory prefix = "\x19Ethereum Signed Message:\n32";
        bytes32 hash = keccak256(abi.encodePacked(prefix, _data));
        address signer = ecrecover(hash, _v, _r, _s);
        return signer;
    }

}

To verify a signature we use the ecrecover in Solidity.

The first parameter to pass is the data that was signed, it needs to be prefixed by "\x19Ethereum Signed Message:\n32" otherwise it won't work.

The next 3 parameters we have to pass are the parts of the signature that we split using the process described above.

The ecrecover function will then return the address that generated the signature for the data that you passed.

You can then check that the address that signed the data is the one that you expected.

And that's it 🎉

Thank you for reading this article