Messages, Transactions, and Clear-Signing
One of the key aspects of blockchains is their immutable nature: once you sign that transaction, there’s no going back. Furthermore, without opening and exposing what’s within a transaction there’s no way of distinguishing whether it’s a transaction of a small value or one which could lead to losing the contents of your wallet. It’s for these reasons, immutability and risk, that it is crucial to know precisely what we’re signing at all times, whether it is for a transaction or a message.
First, a bit of lingo. A “message” is a unit of communication between two or more participants in a blockchain network. It can contain any type of data and they’re commonly used to get digital approval from a user.
A “transaction”, on the other hand, is a specific type of message that involves the transfer of value from one participant to another. It usually includes information such as the sender’s address, the recipient’s address, the amount of cryptocurrency being transferred, and a digital signature that proves the sender’s authorization for the transfer.
Users can already clear sign transactions using their Ledger devices, as detailed in this post, and we’ve extended this good practice using the same principles to messages as well, here’s how.
Why do we sign messages in web3?
Blockchains are based on “public key cryptography”, where users own a public key and a private key, which form a pair. The public key represents the owner’s identity and the private key is secret, allowing them to prove they own the key pair.
When signing a message, you’re using your private key in the signing algorithm to link a signature to the message and public key. No one can derive your private key, or forge a valid signature for you. However, anyone who knows your public key can easily verify that the message was signed by your private key.
Long story short, it’s the same process and idea as signing transactions, except we’re focusing here on signing messages which serve a different purpose: allowance. We’re signing messages in crypto-applications to gather user consent, just as when in real life you’d be using your written signature on a paper. It’s the crypto-version of “fiat signing”.
The importance of EIP-712
Signing messages isn’t a new thing. We’ve been able to sign messages for years now, and those can take different shapes and forms as they improve over time. In fact, the Ethereum Improvement Proposal 191 (EIP-191) was submitted in 2016 and introduced a standard allowing for human-readable messages which is supported natively by Ledger devices. Where EIP-191 fell short though, is that the standard doesn’t structure the data. It’s just a blurb of an unlimited length of data at the end of the message, making it hard to use. In practice, messages are often too long ending up being truncated and resulting in the user missing out on potentially key information; poor UX.
As stated at the beginning of the Ethereum Improvement Proposal 712 (EIP-712): “Signing data is a solved problem if all we care about are bytestrings. Unfortunately in the real world we care about complex meaningful messages.” – I couldn’t agree more. As messages grew to cater for more complex operations, the introduction of typed data structures in messages as specified in EIP-712 was a welcome change.
What this means for users, is that now developers can parse the data in the message and know what is what, which can now be exposed to the user. Parsing means being able to read the contents, because you know how it is structured. That’s a game changer in terms of user experience but also from a security perspective since now I can verify what I’m signing.
Back in the context of what messages are used for, if you’re asking Alice to grant you specific permission on the content of her wallet, as an app developer, you should be super explicit about it to maximize your chances for her to proceed. But it’s more than just a conversion rate optimization.
If you think about security and defense in an adversarial environment, a scammer will obviously make that message as opaque as possible to trick Alice to allow that malicious operation. Transparency and the ability for Alice to double-check what she’s signing are absolutely essential.
And that’s where EIP-712 comes in. Before this EIP, signed messages were an opaque hex string displayed to the user with little context about the items that make up the message.
Would you sign this? Any idea what you’re authorizing here?
The EIP-712 specification introduces typed data structures for messages which allows these to be parsed by wallets and displayed in a user-friendly manner for Alice to make an informed decision. Furthermore, it’s a standard and interoperable across the industry: supporting EIP-712, your message can be parsed by Ledger, MetaMask, Rainbow, Argent, Coinbase Wallet, you name it.
Ledger support for EIP-712
First of all, happy days, Ledger devices have native support for EIP-712 messages, and as a developer you can control precisely how your messages are displayed on the device.
There are essentially 3 levels of support for messages on Ledger devices:
Level 1: Blind Signing
If Bob, an app developer, isn’t using EIP-712 messages, Bob is essentially asking Alice to sign an unreadable hex string: Bob is asking Alice to sign something she can’t even read, that’s blind-signing.
Level 2: Transparent Signing
Implementing an EIP-712 message, Bob is making a step forward going from a hex string to readable content. It now allows Alice to read the content of the message, however, because it’s displaying the full content of the message to her, it’s hard to spot the key information which is mixed with tech information. It’s transparent, but it isn’t clear yet.
Level 3: Clear Signing
Since the device can parse the content of the message, by indicating what to display and how, we can achieve clear signing. So, provided Bob set the required metadata, here’s what Alice would see on her Ledger device:
Much better than a hex string isn’t it?
Another key point is that since it is displayed on a fully secure, separate device which can’t be tampered with, Alice is 100% sure that what she sees on that device is what she’s signing: no malware or malicious application can alter what’s displayed to her. If what’s displayed on the device doesn’t match her expectations, she can stay safe and reject signing the message.
To provide this improved UX and extra security to his users, Bob needs to do 2 things: specify which fields should be displayed to the user and provide a nice, explicit display name for them.
If as a developer you want to join Bob and do it for your app, you have all the documentation here, and it essentially boils down to creating a pull request to whitelist your contract on Ledger’s dApps Asset Registry via a JSON file containing:
- Selectors to indicate which fields the device needs to show Alice,
- Label each selector with a display name.
This isn’t cosmetics, it’s good practice
By whitelisting your smart contract and indicating how Ledger devices can display your messages, not only are you significantly improving the user experience when interacting with your application, but more importantly, you’re protecting all of us from scams and helping build good habits in the web3 ecosystem.
We should never sign something we don’t understand.
We can’t do this without you, help us make clear-signing the norm.