MyCrypto
Published in

MyCrypto

The Magic of Digital Signatures on Ethereum

Signing and verifying messages is an important part of the blockchain, but how does it all work?

What is a cryptographic signature?

When we talk about signatures in cryptography, we talk about some kind of proof of ownership, validity, integrity, etc. For example, they can be used for:

An example of an elliptic curve. Ethereum uses the SECP256k1 curve.

Signing and verifying using ECDSA

ECDSA signatures consist of two numbers (integers): r and s. Ethereum also uses an additional v (recovery identifier) variable. The signature can be notated as {r, s, v}.

  1. Calculate a hash (e) from the message to sign.
  2. Generate a secure random value for k.
  3. Calculate point (x₁, y₁) on the elliptic curve by multiplying k with the G constant of the elliptic curve.
  4. Calculate r = x₁ mod n. If r equals zero, go back to step 2.
  5. Calculate s = k⁻¹(e + rdₐ) mod n. If s equals zero, go back to step 2.
The signature verification passes on MyCrypto. You can try it for yourself here.
  • Calculate the hash (e) for the message to recover.
  • Calculate point R = (x₁, y₁) on the elliptic curve, where x₁ is r for v = 27, or r + n for v = 28.
  • Calculate u₁ = -zr⁻¹ mod n and u₂ = sr⁻¹ mod n.
  • Calculate point Qₐ = (xₐ, yₐ) = u₁ × G + u₂ × R.

The recovery identifier (“v”)

v is the last byte of the signature, and is either 27 (0x1b) or 28 (0x1c). This identifier is important because since we are working with elliptic curves, multiple points on the curve can be calculated from r and s alone. This would result in two different public keys (thus addresses) that can be recovered. The v simply indicates which one of these points to use.

Signed transactions

So far we’ve mostly talked about signatures in the context of messages. Transactions are, just like messages, signed as well before sending them. For hardware wallets like Ledger and Trezor devices, this happens on the device itself. For private keys (or keystore files, mnemonic phrases), this is done directly on MyCrypto. This uses a method that is very similar to how messages are signed, but the transactions are encoded a bit differently.

0xf86c0a8502540be400825208944bbeeb066ed09b7aed07bf39eee0460dfa261520880de0b6b3a7640000801ca0f3ae52c1ef3300f44df0bcfd1341c232ed6134672b16e35699ae3f5fe2493379a023d23d2955a239dd6f61c4e8b2678d174356ff424eac53da53e17706c43ef871
Overview of the transaction parameters on MyCrypto’s broadcast signed transaction page.
  • Encode the transaction parameters: RLP(nonce, gasPrice, gasLimit, to, value, data, chainId, 0, 0).
  • Get the Keccak256 hash of the RLP-encoded, unsigned transaction.
  • Sign the hash with a private key using the ECDSA algorithm, according to the steps described above.
  • Encode the signed transaction: RLP(nonce, gasPrice, gasLimit, to, value, data, v, r, s).

Standardisation of signed messages

There are multiple proposals for defining a standard structure for signed messages. Currently, none of these proposals are finalised, and the personal_sign format, first implemented by Geth, is still the most common. Nonetheless, some of these proposals are very interesting.

"\x19Ethereum Signed Message:\n" + length(message) + message
"\x19Ethereum Signed Message:\n32" + Keccak256(message)

EIP-191: Signed Data Standard

EIP-191 is a very simple proposal: It defines a version number and version specific data. The format looks like this:

0x19 <1 byte version> <version specific data> <data to sign>
  • 0x00: Data with “intended validator.” In the case of a contract, this can be the address of the contract.
  • 0x01: Structured data, as defined in EIP-712. This will be explained further on.
  • 0x45: Regular signed messages, like the current behaviour of personal_sign.

EIP-712: Ethereum typed structured data hashing and signing

Not to be confused with ERC-721, the non-fungible token standard, EIP-712 is a proposal for “typed” signed data. This makes signing data more verifiable, by presenting it in a human-readable way.

Signing a message with MetaMask. The old signed transaction interface (using personal_sign) on the left, the new one (using EIP-712) on the right.
0x1901fb502c9363785a728bf2d9a150ff634e6c6eda4a88196262e490b191d5067cceee82daae26b730caeb3f79c5c62cd998926589b40140538f456915af319370899015d824eda913cd3bfc2991811b955516332ff2ef14fe0da1b3bc4c0f424929

Verifying signatures with smart contracts

What makes message signatures more interesting is that we can use smart contracts to verify the ECDSA signatures. Solidity has a built-in function called ecrecover (which is actually a precompiled contract at address 0x1) that will recover the address of the private key that a message was signed with. A (very) basic contract implementation looks like this:

Conclusion

Signatures are a key part of the blockchain and decentralisation. Not only for sending transactions, but also for interacting with decentralised exchanges, multisig contracts, and other smart contracts. There is no clear standard for signing messages yet, and further adoption of the EIP-712 specification would help the ecosystem to improve the user experience, as well as to have one standard for message signatures.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store