Digital signatures play a crucial role in ensuring the security, authenticity, and authorization of various operations within a decentralized application. It’s important to know that the individual you are interacting with is indeed who they claim to be.
const signMessage = async (message) => {
try {
if (connectedWallet) {
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = provider.getSigner();
const signature = await signer.signMessage(message);
const address = await signer.getAddress();
return {
signature,
address,
};
}
} catch (err) {
console.log(err);
}
};
When the signMessage
method is called from the example above, it will first verify that your wallet is indeed connected to the decentralized application. It then creates a new provider instance using your connected wallet, accessing your signer details.
A Signer in ethers is an abstraction of an Ethereum Account, which can be used to sign messages and transactions and send signed transactions to the Ethereum Network to execute state changing operations.
Now that we are able to sign, we require something to sign. The message can be either a string or in the form of an Uint8Array and will be signed complying with the EIP-191 standard. If the message is a string, it is signed as UTF-8 encoded bytes. It is not interpreted as as BytesLike; so the string 0x1234
is signed as six characters, not two bytes. To sign that example as two bytes, the Uint8Array should be used. (i.e. new Uint8Array([ 0x12, 0x34 ])
).
Lets provide the message string, Don’t wish for it. Work for it
You’re going to be prompted by your connected wallet to review the message and by clicking sign, you’re using your private key to encrypt that hash digest/value, a.k.a the message, to create the digital signature.
This action produces a signature like this.
0xee9198263e0fba336d9a9e66b76f2819066adeb65875319390ae01da0c323fff70ed95037af516c2076182a8f74cc88d9cef2a6e151cba13b1f395ca10f4dc071b
Decoded it looks like this.
r | 0xee9198263e0fba336d9a9e66b76f2819066adeb65875319390ae01da0c323fff |
s | 0x70ed95037af516c2076182a8f74cc88d9cef2a6e151cba13b1f395ca10f4dc07 |
v | 27 |
We will spare you the deep dive on the what and how of R,S,V. For now it’s enough to understand that R & S are encoded hashes related to your private key through the use of elliptic-curve cryptography and they cannot reveal the private key. V is added to the signature verification function to help detect the correct value of R **as it can produce two possible generated values. If V is even, the R is the correct value, if V is odd, then R’.
Congratulations! You have signed a message with your wallet. The decentralized application is now going to take that raw message and the digital signature to complete it’s verification process.
const verifyMessage = async ({ message, address, signature }) => {
try {
const signerAddr = await ethers.utils.verifyMessage(message, signature);
if (signerAddr !== address) {
return false;
}
return true;
} catch (err) {
console.log(err);
return false;
}
Behind the scenes when verifying the message it uses the secp256k1 elliptic-curve algorithm. It takes the message and the signature verification variables v, r, s, and returns an address. The returned address can then be compared against other addresses to complete the security, authenticity, or authorization process from within your decentralized application.
Try it yourself
If you would like to try this out for yourself, you can use this tool I created to sign and verify messages. https://digital-signatures.jasonschwarz.xyz
Why sign messages?
Here are some examples of when your signature would be required. These examples showcase the versatility of message signing in blockchain applications, providing a secure and verifiable way to interact with data and systems without necessarily involving financial transactions.
- Authentication in DApps:
Users signing messages to authenticate themselves within decentralized applications (DApps) without initiating a transaction.
- Digital Agreements:
Signing messages to create or acknowledge digital agreements, contracts, or consent within a blockchain-based system.
- Proof of Ownership:
Demonstrating ownership or authorship of digital assets, intellectual property, or content by signing a message.
- Credential Verification:
Verifying credentials or qualifications by signing a message containing relevant information.
- Message Endorsement:
Endorsing messages or content on social platforms or forums to confirm the authenticity of the endorsement.
- Non-Repudiation:
Ensuring non-repudiation by signing messages, making it difficult for the signer to deny their involvement or agreement.
- Identity Verification:
Verifying identity without the need for a transaction, often in scenarios like account recovery or access to secured information.
- Confirmation of Actions:
Confirming specific actions or decisions without initiating a transaction, providing a digital trail of consent or authorization.
- Secure Communication:
Signing messages in secure communication channels, ensuring the integrity and authenticity of the communicated information.
- Attestation of Data:
Attesting to the accuracy or authenticity of data by signing a message containing relevant information.
- Acknowledgment of Receipt:
Acknowledging the receipt of information, goods, or services without necessarily involving a transaction.
- Decentralized Governance:
Participating in decentralized governance by signing messages to express voting preferences or decisions.
- Selective Disclosure of Information:
Selectively disclosing certain information without revealing the entirety of one's identity or data, using signed messages for privacy.
- Timestamping:
Signing messages to create timestamps for events or data, ensuring a secure record of when certain actions occurred.
- Consent Confirmation: Confirming consent for specific actions or data sharing without engaging in a full-fledged transaction.
Conclusion
As we reflect on the importance of digital signatures in the blockchain domain, we find compelling reasons to incorporate this cryptographic practice into our decentralized applications. It instills confidence in users, assuring them that their actions are authenticated and authorized with the utmost integrity.
In essence, the code, sign, secure paradigm becomes a guiding principle for DApp developers and users alike. The seamless integration of Ethers.js empowers us to navigate the decentralized frontier with confidence, fostering a trust-rich environment where digital signatures can serve as the guardians of authenticity and security.