How to Verify a Signed Message in Solidity

Leon Do
June 15, 2022

Introduction

This is a practical tutorial on signing a message using MetaMask and then verifying it on-chain.

Here’s a demo: https://leon-do.github.io/ecrecover/

Signing

-- CODE language-js line-numbers --

Note

  • This is using the method personal_sign to prevent accidental transaction spending. This will relate to \x19Ethereum Signed Message:\n32 prefix found in the smart contract (below).
  • This is signing the hashed message.

Signature

Below is the required information to verify a signature. Use this in your smart contract.

-- CODE language-js line-numbers -- hashedMessage = 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8 r = 0xb7cf302145348387b9e69fde82d8e634a0f8761e78da3bfa059efced97cbed0d s = 0x2a66b69167cafe0ccfc726aec6ee393fea3cf0e4f3f9c394705e0f56d9bfe1c9 v = 28

Smart Contract

Create the solidity contract.

-- CODE language-js line-numbers -- // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Verify { function VerifyMessage(bytes32 _hashedMessage, uint8 _v, bytes32 _r, bytes32 _s) public pure returns (address) { bytes memory prefix = "\x19Ethereum Signed Message:\n32"; bytes32 prefixedHashMessage = keccak256(abi.encodePacked(prefix, _hashedMessage)); address signer = ecrecover(prefixedHashMessage, _v, _r, _s); return signer; } }

Note

  • Notice the prefix,\x19Ethereum Signed Message:\n32 is required to verify a signed message.
  • The prefix is hashed along with the message.
  • ecrecover should return the address of the signer.

Verify in Solidity

Input the hashed message and signature (r, s, v) to verify the address.

Use Case: Unity Gaming

  • Game developer creates a game, server, and smart contract that issues prizes if the player wins.
  • Player wins and tells the game developer they won.
  • Game server provides the player with a signature (explained above) that allows the user to claim. Think of this as a coupon.
  • Player then interacts with the contract and submits the signature (coupon) to claim their prize.

Example smart contract deployed by game developer:

-- CODE language-js line-numbers -- // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // game developer depoloys contract contract Verify { // game developer's account address public owner = 0xdD4c825203f97984e7867F11eeCc813A036089D1; // player claims price function claimPrize(bytes32 _hashedMessage, uint8 _v, bytes32 _r, bytes32 _s) public view returns (bool) { bytes memory prefix = "\x19Ethereum Signed Message:\n32"; bytes32 prefixedHashMessage = keccak256(abi.encodePacked(prefix, _hashedMessage)); address signer = ecrecover(prefixedHashMessage, _v, _r, _s); // if the signature is signed by the owner if (signer == owner) { // give player (msg.sender) a prize return true; } return false; } }

After winning, the player gets a signature (coupon) from the game server to claim their prize

0xb7cf302145348387b9e69fde82d8e634a0f8761e78da3bfa059efced97cbed0d2a66b69167cafe0ccfc726aec6ee393fea3cf0e4f3f9c394705e0f56d9bfe1c91c

Player parses the signature in Unity

-- CODE language-js line-numbers -- string signature = "0xb7cf302145348387b9e69fde82d8e634a0f8761e78da3bfa059efced97cbed0d2a66b69167cafe0ccfc726aec6ee393fea3cf0e4f3f9c394705e0f56d9bfe1c91c"; string r = signature.Substring(0, 66); string s = "0x" + signature.Substring(66, 64); int v = int.Parse(signature.Substring(130, 2), System.Globalization.NumberStyles.HexNumber);


The player can then interact with the smart contract to claim their prize. More information here.

true means the player received their prize

Conclusion

Got further questions? Hop into our Discord — we’ve got a thriving community ❤️‍🔥

#off-topic-lounge for general inquiries.

#gaming-general for gaming development chat.

#gaming-showcase to show your stuff.

About ChainSafe

ChainSafe is a leader in blockchain development and infrastructure solutions for web3. We’re working toward a more decentralized future by building client implementations for Ethereum, Filecoin, Polkadot, and Mina. We’re also maintaining the web3.js library, working on a Gaming SDK that connects NFTs to Unity, building a distributed cloud storage application, and bootstrapping a multi-chain bridge. To learn more, click here.

Want to help build the foundations of web3? Join us!

Have a question, comment, or suggestion? Drop into our Discord and join the conversation! We’re also always looking for talented people. Check out our open positions and get in touch ➡️➡️ [email protected]

More articles