In this tutorial, we are going to learn how to sign data using a wallet and verify that the signature was generated with the right wallet using Ethers JS. We will learn how to get the address that generated the signature.
Requiring the user to sign data using their wallet is a great way to authenticate users and make sure that they have access to the wallet they claim to have access to.
Check out this tutorial if you want to learn how to implement an authentication system with Ethereum.
Here is the full code to sign data and verify a signature:
const ethers = require("ethers") const provider = new ethers.providers.Web3Provider(YOUR_PROVIDER_HERE) // the data to sign, it can be any string const dataToSign = "1234567890" // sign data using the connected wallet const signer = provider.getSigner() const signature = await signer.signMessage(dataToSign) // verify the signature and get the address that generated the signature for the data passed const signerAddress = ethers.utils.verifyMessage(dataToSign, signature)
Let's break down this code.
First, we need to have a message to sign which can be any string value. You can also sign an array of bytes but we're not going to see that here as we usually don't need to do that.
Then, we get a
Signer which is the wallet that will sign the data and we call the
signMessage function and pass the string to sign as a parameter.
const signature = await signer.signMessage("TEST") // Signing the string "TEST" with this address: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 // returns this signature: //0x8045b07f2f3ef63282399b3d898fe0dcadc6b9693d9164d7f8e542bc14b3d82b40b94abc211e82e817160190d5e890ade6d69ab883205f4126347e2cee021e661b
signMessage function returns a Promise which returns the signature when it's resolved.
The signature will be an hexadecimal string of 65 bytes like this one:
Once you have the signature, you can use the
ethers.utils.verifyMessage function to recover the address that signed the data and generated the signature.
Here is an example with the signature above:
const signature = "0x8045b07f2f3ef63282399b3d898fe0dcadc6b9693d9164d7f8e542bc14b3d82b40b94abc211e82e817160190d5e890ade6d69ab883205f4126347e2cee021e661b" const data = "TEST" const addressThatSignedData = ethers.utils.verifyMessage(data, signature) // the address that signed the data is: // 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
ethers.utils.verifyMessage will return the address that generated the signature passed in the second parameter for the data passed in the first parameter.
The address returned will be a string. In the example above, it's going to be:
If you want to do the verification part in a Solidity smart contract, it's going to be slightly different. If you want to learn how to do this, check out this tutorial on how to verify a signature with Solidity:
You'll have to split the signature into smaller chunks of specific sizes as explained at the end of this tutorial.
Lastly, if you want to learn more about signatures, you can read this Wikipedia page about Digital signatures and the cryptography behind it.
And that's it 🎉
Thank you for reading this article