A Comprehensive Guide to Ethereum Signatures: ECDSA, RLP, EIP155, EIP191, and EIP712

·

Mind Map

Ethereum signatures can be categorized into message signing and transaction signing, both based on the ECDSA algorithm. This guide explores both processes in detail.


Signature Overview

Purpose of Signatures:

Learn more: Digital Signatures (Wikipedia).


Understanding Signatures

What is a Signature?

In Ethereum, a signature is a data string serving the same purpose as a handwritten signature:

Key Takeaway: Ethereum signatures functionally match real-world contract signatures.

Signature Workflow:

  1. Signing:
    ECDSA_ForwardAlgorithm(message + private key + nonce) → Signature (r, s, v)
  2. Verification:
    ECDSA_ReverseAlgorithm(message + signature) → Public Key

Ethereum’s ECDSA extends the standard with v for chain ID support.


Transaction Signing

Key Concepts:

Transaction Signing Flow:

1. Construct Raw Transaction:

{
  nonce:        // Transaction count of sender
  gasPrice:     // Gas price (Gwei)
  gasLimit:     // Max gas allocated
  to:           // Recipient address (null for contract deployment)
  value:        // Ether amount
  data:         // Contract bytecode or function call data
  chainId:      // EIP155 chain ID (e.g., 1 for Ethereum)
}

2. Signing Process (via MetaMask/ethers.js):

const ethers = require("ethers");
const tx = {
  nonce: 0,
  gasPrice: ethers.utils.parseUnits("10", "gwei"),
  gasLimit: 100000,
  to: "0x...",
  value: 0,
  chainId: 1
};
const signedTx = await wallet.signTransaction(tx); // RLP + Keccak256 + ECDSA

3. Verification:

Nodes decode RLP → recover sender’s address via ecrecover → validate against public key.

Security Measures:


Message Signing (Pre-Signed Messages)

Use Cases:

Generic Method (MetaMask personal_sign):

  1. Hash parameters: keccak256(abi.encodePacked(account, tokenId)).
  2. Prefix with \x19Ethereum Signed Message:\n32.
  3. Sign with private key.

Example NFT Whitelist Contract:

function recoverSigner(address account, uint256 tokenId, bytes memory signature) public pure returns (address) {
  bytes32 msgHash = keccak256(abi.encodePacked(account, tokenId));
  bytes32 ethMsgHash = ECDSA.toEthSignedMessageHash(msgHash);
  return ECDSA.recover(ethMsgHash, signature);
}

EIP712: Structured Message Signing

Advantages:

Structure:

  1. Domain Separator:

    keccak256(
      abi.encode(
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
        keccak256("Uniswap V2"),
        keccak256("1"),
        chainId,
        contractAddress
      )
    );
  2. Message Hash:
    Encode custom structs (e.g., Permit) with type hashes.

Uniswap V2 Example:

bytes32 digest = keccak256(
  abi.encodePacked(
    "\x19\x01",
    DOMAIN_SEPARATOR,
    keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonce, deadline))
  )
);

FAQ

Q: Why does EIP712 include chainId?

A: To prevent replay attacks across different chains (e.g., Ethereum vs. Ethereum Classic).

Q: How does RLP ensure transaction consistency?

A: It serializes data deterministically so hash outputs match during verification.

Q: What’s the gas advantage of EIP712?

A: Bundles approvals into single transactions (e.g., Uniswap’s permit saves 50% gas).


Conclusion

Ethereum signatures combine cryptography and usability. From basic ECDSA to EIP712’s structured messages, each method addresses specific security and efficiency needs.

👉 Explore advanced Ethereum tools
👉 Deep dive into EIP712

References:

  1. EIP191 Standard
  2. EIP712 Explained
  3. RLP Encoding Guide

Key SEO elements: