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:
- Authentication: Prove ownership of a private key linked to an address.
- Non-repudiation: Confirm the origin of a message.
- Integrity: Ensure message content remains unaltered.
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:
- Nodes (miners/validators) use it to verify identity (only the private key holder can generate it).
- Tampering is detectable due to cryptographic integrity checks.
Key Takeaway: Ethereum signatures functionally match real-world contract signatures.
Signature Workflow:
- Signing:
ECDSA_ForwardAlgorithm(message + private key + nonce) → Signature (r, s, v) - Verification:
ECDSA_ReverseAlgorithm(message + signature) → Public Key
Ethereum’s ECDSA extends the standard with v for chain ID support.
Transaction Signing
Key Concepts:
- RLP Encoding: Ensures consistent serialization for Keccak256 hashing (critical for transaction verification).
Details: Ethereum RLP Encoding. - Keccak256: Ethereum’s hash function (32-byte output).
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 + ECDSA3. Verification:
Nodes decode RLP → recover sender’s address via ecrecover → validate against public key.
Security Measures:
- Nonce: Prevents double-spending.
- ChainId: Blocks cross-chain replay attacks (EIP155).
Message Signing (Pre-Signed Messages)
Use Cases:
- NFT whitelists
- Contract permissioning (e.g., Uniswap’s
permit)
Generic Method (MetaMask personal_sign):
- Hash parameters:
keccak256(abi.encodePacked(account, tokenId)). - Prefix with
\x19Ethereum Signed Message:\n32. - 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:
- Human-readable signatures (shown in wallets like MetaMask).
- Prevents replay attacks via domain separation.
Structure:
Domain Separator:
keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256("Uniswap V2"), keccak256("1"), chainId, contractAddress ) );- 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:
Key SEO elements: