How to sign & verify an Ethereum message off chain

Cryptographic signatures have many different use cases in the Ethereum ecosystem. Signatures are used for verification of ownership, payments, authorization, etc. The combination of smart contracts and cryptographic signatures allow payments to be made off chain for a future date and time. This is similar to writing checks to pay for a product or service. In this tutorial we will focus on how to sign and verify signatures in Ethereum off chain. This will be the beginning of a two part introduction on how to setup a payment channel.

How to encrypt and sign a message in Ethereum

The process below will demonstrate how one can use a smart contract and web3 to achieve signing a message off chain. Transactions are not written to the blockchain.

How to sign and verify an Ethereum message off chain

To keep it simple we will:

  • First use Remix to encrypt / hash a message in keccak256
  • Make sure you have MetaMask installed and you are logged in to the test network
  • Then use the web browser to sign the message in MetaMask

Deploy a smart contract in Remix to hash a string and verify signatures

First create a simple contract in Remix that contains the three functions below. These functions are:

  • getHash – Used to hash a string
  • getEthSignedHash – Takes the getHash results and prefixes with “\x19Ethereum Signed Message” and hashes the message again
  • verify – allows you to input the getEthSignedHash results and the users signature hash results to determine what Ethereum account signed the transaction
pragma solidity ^0.7;

contract VerifySignature {
    
    
    // use this function to get the hash of any string
    function getHash(string memory str) public pure returns (bytes32) {
        return keccak256(abi.encodePacked(str));
    }
    
    
    // take the keccak256 hashed message from the getHash function above and input into this function
    // this function prefixes the hash above with \x19Ethereum signed message:\n32 + hash
    // and produces a new hash signature
    function getEthSignedHash(bytes32 _messageHash) public pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _messageHash));
    }
    
    
    // input the getEthSignedHash results and the signature hash results
    // the output of this function will be the account number that signed the original message
    function verify(bytes32 _ethSignedMessageHash, bytes memory _signature) public pure returns (address) {
        (bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);
        return ecrecover(_ethSignedMessageHash, v, r, s);
    }
}    

Try it in Remix

After the contract is locally deployed hash the word “hello”. The Keccak256 algorithm will generate an alpha numeric hash string.

How to sign and verify an Ethereum message off chain remix

Since we do not have any Web3 code written we will type several commands manually in the bowser to illustrate how this could work. Naturally this process would be automated in a decentralized application.

Use the web browser to sign an Ethereum transaction

Next, in your browser press F12 to launch your developer console. This console will allow you to write simple commands and inspect code. Clear the console to remove any text that is present on the screen. We will type in a few commands that will interact with MetaMask and Ethereum.

How to sign and verify an Ethereum message off chain browser

Type the word hash = “hash generated in Remix” and paste in the hash that you generated in Remix and press enter. This will create a variable called hash which we will use in a future function.

How to sign and verify an Ethereum message off chain browser

Then type ethereum.enable().then(console.log). A promise message will display to indicate the default account in MetaMask. The account displayed will be used to sign the transaction.

How to sign and verify an Ethereum message off chain browser

Copy your account number and assign it to a variable named account which we will use in a future function. Type account = “your MetaMask account”.

How to sign and verify an Ethereum message off chain browser

Type ethereum.request({method: “personal_sign”, parms: [account, hash]}).then(console.log) which will initiate signing the hash. The method “personal_sign” takes the parameters account and hash (which you set above). Your MetaMask wallet will popup asking if you approve or reject signing the message. Confirm that the hash you entered in the console is the same hash you are signing with your wallet.

How to sign and verify an Ethereum message off chain browser metamask

After pressing “Sign” in MetaMask your signed hash will display in the console. This hash is used to confirm the message was signed by your private key.

How to sign and verify an Ethereum message off chain browser

How to determine the account that signed a message

Return to your contract in Remix and copy the “hello” hash from the getHash function and paste it in the getSignedHash function. This function prefixes the hash above with \x19Ethereum signed message:\n32 + hash and produces a new hash signature. This is preparation for the final verification step.

How to sign and verify an Ethereum message off chain browser remix

Finally take the hash that getEthSignedHash generated and the signed hash from your browser above and input both hash’s into the verify function in Remix. The verify function will display the account that signed the transaction. If the account is different in Remix that means a different account signed the message or something went wrong in the process.

How to sign and verify an Ethereum message off chain browser remix

This was a simple example of how to create a hash, sign it with your wallet and verify the account that signed the message. This can be implemented using a combination of a smart contract in solidity and Web3 in Python or JavaScript.

This code is for learning and entertainment purposes only. The code has not been audited and use at your own risk. Remember smart contracts are experimental and could contain bugs.

Click here for more information about how to use the Ethereum test network and how to obtain test ETH.

Next Review – How to create a payment channel on Ethereum

Ledger Nano X - The secure hardware wallet

Leave a Reply