EIP-191 is a specification for a versioned, structured data format for signed messages on Ethereum. Its primary purpose is to prevent a critical security flaw where a user might unknowingly sign a raw transaction that could be maliciously submitted for execution. By introducing a standard preamble, it ensures a signature is explicitly bound to a specific, intended context, making signatures non-malleable and context-specific. This is a foundational security primitive for user interactions.
EIP-191
What is EIP-191?
EIP-191 is a formal Ethereum Improvement Proposal that defines a standard data format for signed messages, providing a structured way to verify that a user approved a specific piece of data.
The standard defines a simple structure: 0x19 <version byte> <version-specific data> <data to sign>. The initial 0x19 byte is a deliberate guard, as this byte would rarely appear in a raw RLP-encoded Ethereum transaction, preventing accidental transaction replay. The version byte dictates how the subsequent data is interpreted. Version 0x00 is for data with an optional validator address, 0x01 is for structured data as defined by EIP-712, and 0x45 ("E") is for personal_sign messages, which is the most common implementation used by wallets like MetaMask.
The most widespread application of EIP-191 is in wallet signature requests for login and authentication, often via the personal_sign method (version 0x45). When a dapp asks you to "Sign in with Ethereum," it is typically using this standard to generate a cryptographic proof of ownership of an address without requiring a transaction or paying gas. This signature can then be verified off-chain by the service. The structured format prevents the signed message from being misinterpreted as a transaction or used in a different dapp's context.
Beyond simple logins, EIP-191 is the essential precursor to EIP-712, which enables signing of complex, human-readable structured data. While EIP-191 provides the versioned envelope, EIP-712 defines a schema for the data inside that envelope, allowing users to see a clear breakdown of what they are signing. Together, these standards form the backbone of secure, user-consent mechanisms for meta-transactions, delegated approvals, and gasless transactions in the Ethereum ecosystem.
For developers, implementing EIP-191 verification is crucial for security. A contract must replicate the exact same data formatting on-chain that was signed off-chain. This involves prepending the 0x19 byte, the version, any length prefixes, and finally the intended message data, then using ecrecover to check the signature against the signer's address. Failing to adhere precisely to the standard can create signature malleability vulnerabilities, where a valid signature for one purpose could be reused for another.
How EIP-191 Works
An explanation of the Ethereum Improvement Proposal that defines a standard for signed data messages, enabling secure and verifiable off-chain communication.
EIP-191 is a standard for signed data with intended validator that defines a structured data format for creating verifiable signatures on arbitrary messages. It specifies a version byte and a domain separator to prevent signature reuse across different contexts, a problem known as a replay attack. This standard is foundational for secure off-chain interactions like meta-transactions, login requests, and vote delegation, as it allows a user to sign a message with their private key, which can later be verified on-chain without submitting a full transaction.
The standard defines a specific encoding format, beginning with a 0x19 byte, followed by a version-specific identifier. The most common version, 0x45 (E), is for Ethereum Signed Messages used by wallets like MetaMask for simple text. The version 0x00 is for structured data with an intended validator address, which prepends the signer's address to the message before hashing. This structure ensures a signature created for one smart contract cannot be replayed on another, even if the message data is identical, by binding the signature to a specific contract address.
For developers, implementing EIP-191 involves hashing the message according to the standard's rules: \x19Ethereum Signed Message:\n + length + message for version 0x45, or \x19\x00 + validator address + data for version 0x00. The resulting hash is then signed using ecrecover. Smart contracts verify these signatures using the ecrecover precompile, which returns the signer's address from the signature and hash. This mechanism is the backbone of systems like EIP-712 for typed structured data and ERC-2771 for meta-transactions, providing a secure and standardized method for trust-minimized off-chain agreement.
Key Features
EIP-191 is a standard for structured data signing in Ethereum, defining a version byte and optional validator address to prevent signature reuse across different contexts.
Version Byte & Purpose
The standard defines a version byte (0x19) as a prefix to all signed messages. This byte serves as a version identifier and a guard against replay attacks by ensuring signatures are only valid for the specific EIP-191 format. It prevents a signature for a plain string from being misinterpreted as a signature for structured data.
Structured Data Hash (Type `0x01`)
This format is used for signing typed structured data as defined by EIP-712. The message is prefixed with \x19\x01. It includes:
- The domain separator, which binds the signature to a specific contract and chain.
- The structured data hash of the message contents. This creates signatures that are human-readable, verifiable off-chain, and secure against replay.
Validator Address (Type `0x00`)
This format is designed for contract-based signature validation. The message is prefixed with \x19\x00 and includes the address of the validator contract. This ensures the signature is only valid when verified by that specific contract, preventing signatures from being replayed on different contracts or in different contexts.
Arbitrary Data (Type `0x45` / `\x19Ethereum Signed Message:\n`)
This is the legacy format for signing arbitrary strings or binary data, commonly used by wallets like MetaMask for off-chain authentication. The message is prefixed with the string "\x19Ethereum Signed Message:\n" plus the message length. While not part of the final EIP-191 spec, it is the de facto standard referenced by it for personal_sign messages.
Preventing Signature Malleability
A core security feature of EIP-191 is preventing signature malleability across contexts. By using distinct, unforgeable prefixes (like \x19\x01), a signature created for one purpose (e.g., a login) cannot be replayed for another (e.g., a token transfer), even if the underlying data is identical.
Implementation & Usage
EIP-191 is implemented in libraries like OpenZeppelin's EIP712 and is the foundation for:
- Gasless transactions (via EIP-712 signatures).
- Off-chain authorization for DAO votes or marketplace orders.
- Secure login protocols (Sign-In with Ethereum).
Developers use
encodePackedwith the correct prefix to reconstruct the signed message hash for verification.
EIP-191 Version Breakdown
A detailed examination of the structured data format for signed messages defined in Ethereum Improvement Proposal 191, outlining its purpose, version specifications, and implementation.
EIP-191 is a standard for a structured data format for signed messages on Ethereum, designed to prevent the signing of raw, arbitrary data which can be replayed or misinterpreted by different applications. Prior to its adoption, signing a plain text string like "Send 100 ETH" was dangerous, as the same signature could be valid for a different contract expecting a different meaning. EIP-191 introduces a version byte and specific formatting to create domain separation, ensuring a signature is only valid within its intended context. This prevents signature replay attacks across different smart contracts and dApps.
The proposal defines three distinct version structures, each prefixed with the byte 0x19. Version 0x00 is for data with an intended validator, where the format is 0x19 || 0x00 || validator_address || data. This is commonly used by personal_sign methods in wallets, where the validator is implicitly the signer's own address. Version 0x01 is for structured data as defined by EIP-712, which enables human-readable signing in wallets. Its format is 0x19 || 0x01 || domainSeparator || hashStruct(message), providing a robust framework for signing complex, typed data.
Version 0x45 ("E" in ASCII) is designated for Ethereum Signed Messages, formalizing the common pattern used by wallets like MetaMask for personal_sign. The format is 0x19 || "Ethereum Signed Message:\n" || message.length || message. This version explicitly includes the message length to prevent ambiguity, making it the standard for simple message signing where no specific validator or complex structure is required. The 0x19 prefix was chosen as it is an unused opcode in the Ethereum Virtual Machine (EVM), making it unlikely to appear in valid transaction data.
Implementing EIP-191 requires developers to correctly prefix their message hashes before signing. For example, a contract verifying a Version 0x45 signature must reconstruct the prefixed message \x19Ethereum Signed Message:\n32 followed by the 32-byte Keccak-256 hash of the original message. This process is abstracted by libraries like OpenZeppelin's ECDSA library, which provides functions for recovering signer addresses from EIP-191 compliant signatures. Failure to use the correct prefix and version makes signatures invalid and contracts insecure.
The primary use cases for EIP-191 are meta-transactions (via ERC-2771), login authentication (Sign-In with Ethereum), token permit functions (ERC-2612), and off-chain agreement signing. By providing a clear versioning system, EIP-191 ensures interoperability and security across the ecosystem. It is a foundational standard that enables trust-minimized interactions by allowing users to sign messages off-chain that can be reliably verified and executed on-chain, forming the basis for more complex signature-based protocols.
EIP-191: Signed Data Standard
EIP-191 is a formal standard defining a structured format for signing arbitrary data (messages) on Ethereum, enabling secure off-chain message verification.
EIP-191 specifies a versioned, structured data format for Ethereum signed messages. Before its adoption, signing messages lacked a standard, leading to security risks where a signature for one application could be replayed in another. The standard introduces a version byte and optional domain separator to prevent such signature replay attacks and ensure the signed data's intent is unambiguous. This is crucial for meta-transactions, login authentication (like Sign-In with Ethereum), and off-chain agreements.
The standard defines several version structures. The most common, version 0x45 (E), is the legacy \x19Ethereum Signed Message:\n prefix used by personal_sign. Version 0x00 is for data with a verifier-specific validator address, while version 0x01 is the structured data format defined by EIP-712, which enables human-readable signing. Each version byte ensures signatures are context-bound, meaning a signature for a login cannot be misinterpreted as authorization for a token transfer.
Implementing EIP-191 involves hashing the data with the appropriate version-specific prefix before signing. For example, to sign a plain text message, a developer would prepend the \x19Ethereum Signed Message:\n prefix and the message length before hashing with Keccak-256. The resulting hash is then signed with the user's private key using ecdsa recovery. Contracts verify these signatures using the ecrecover precompiled function, which returns the signer's address from the signature and the hash.
A primary use case is gasless transactions or meta-transactions. A user can sign a transaction message off-chain (following EIP-191) and send the signature to a relayer. The relayer pays the gas to submit the transaction to a smart contract, which uses ecrecover to validate the user's signature and execute the intended logic. This pattern is fundamental to systems like OpenZeppelin's Defender Relayer and many decentralized application (dApp) user experiences.
EIP-191's true power is realized with EIP-712: Typed Structured Data Hashing. This extension (version 0x01) allows signing human-readable, typed data structures instead of opaque hex strings. The signer's wallet can display a clear representation of the data being signed (e.g., "Sign this order to trade 100 DAI for 1 ETH"), vastly improving security and user experience for complex agreements like decentralized exchange orders or DAO votes.
Ecosystem Usage
EIP-191 provides a simple, flexible standard for signing structured data on Ethereum. Its primary use case is to prevent transaction replay attacks and enable secure off-chain message signing for applications like login and authorization.
Vote Delegation & Governance
Governance protocols like Compound and Uniswap use EIP-191 signatures for gasless vote delegation. A token holder signs a structured message authorizing a delegate to vote on their behalf. This signature is submitted by a relayer, saving the delegator gas fees and streamlining the governance process.
Meta-Transactions & Gas Abstraction
Account Abstraction (ERC-4337) and relayers use EIP-191 to sign UserOperations. The signature covers the operation's intent, allowing a third-party paymaster to sponsor the gas fees. This enables users to interact with dApps without holding the native blockchain token for gas.
Off-Chain Agreements & Commitments
Applications use EIP-191 to create verifiable, signed commitments off-chain before submitting them on-chain. Examples include:
- Signing limit orders for DEXs (like 0x).
- Approving the terms of a smart contract interaction.
- Creating provable attestations or claims that can be verified later, reducing on-chain congestion.
Preventing Replay Attacks
The core security feature of EIP-191 is its structured data format, which includes a version byte (0x19), a verifier-specific data field (often the contract address), and the actual data. This structure ensures a signature is valid only for a specific smart contract and context, preventing it from being replayed on a different chain or against a different contract.
Security Considerations
EIP-191 defines a standard for signed data with a version byte and optional validator address, enabling secure off-chain message signing for applications like login and transaction authorization.
Version Byte & Structure
The standard defines a structured data format prefixed by 0x19. The version byte determines the structure:
0x00: Data intended for a specific validator (e.g.,\x19\x00<validator address><data>).0x01: Structured data as defined by EIP-712.0x45(E):\x19Ethereum Signed Message:\n<len(message)><message>, the format used bypersonal_sign. This prevents signed messages from being valid Ethereum transactions.
Replay Attack Prevention
A core security feature is preventing replay attacks, where a signature valid in one context is reused maliciously in another. The standard mitigates this through context-specific prefixes. For version 0x00, the inclusion of a validator address (e.g., a smart contract) ensures the signature is only valid for that specific verifier. Applications must also implement their own safeguards, such as including nonces or chain IDs within the signed data payload itself.
Validator-Specific Signatures (0x00)
This version binds a signature to a specific verifying contract, a pattern critical for meta-transactions and gasless transactions. The structure is: \x19\x00<validator address><data>. Security depends on the verifier contract correctly reconstructing this exact bytestring. A major risk is signature malleability if the verifier does not enforce the exact format, potentially allowing signatures to be replayed across different contracts or contexts.
EIP-712 Structured Data (0x01)
EIP-191's 0x01 version byte is reserved for EIP-712 typed structured data. This allows signing human-readable, type-safe data structures, providing superior security and UX over raw hex. The signer can clearly verify what they are signing. The security model relies on the domain separator, which includes chainId and verifyingContract to prevent cross-chain and cross-contract replay attacks. Correct implementation of the domain separator is paramount.
`personal_sign` Compatibility (0x45)
The \x19Ethereum Signed Message:\n prefix (version 0x45) is the format used by common RPC methods like personal_sign. Its primary security purpose is to provide a domain separation from native Ethereum transactions. Without it, a signed message could be interpreted as a signed transaction. Wallets display this prefix to users. Developers must ensure the message length is correctly encoded to match the wallet's implementation and avoid signature incompatibility.
Implementation Audit Checklist
When implementing EIP-191 verification, audit for these critical points:
- Prefix Enforcement: The verifier must require the exact
0x19and version byte. - Replay Guards: For
0x00, validate thevalidator addressmatches the verifier. For all versions, consider adding nonces, deadlines (deadline), or chain IDs (chainId) to the signed data. - EIP-712 Domain: For
0x01, ensure thedomainSeparatoris calculated correctly and includeschainIdandverifyingContract. - Signature Validation: Use
ecrecoveror a library that returns the signer's address, and verify it matches the expected authority.
EIP-191 vs. Other Signing Methods
A technical comparison of structured data signing (EIP-191) with other common signature schemes used in Ethereum and Web3.
| Feature / Attribute | EIP-191 (Structured Data) | Raw ECDSA (EIP-155) | EIP-712 (Advanced Structured) |
|---|---|---|---|
Primary Purpose | Human-readable prefix for replay protection | Direct signature of transaction data | Type-safe, human-verifiable structured data |
Signature Format |
| Raw R, S, V from | Domain separator + type hash + encoded data |
Human Readability | Basic (identifies purpose) | None (raw bytes) | High (displays structured fields to user) |
Replay Protection | β (via domain/version in v1) | β (via chain ID in EIP-155) | β (via domain separator) |
Standardization | Ethereum Improvement Proposal | Core cryptographic primitive | Ethereum Improvement Proposal |
Typed Data Support | β | β | β |
Common Use Case | Simple login messages, basic approvals | Transaction signing (pre-EIP-155) | Complex DApp interactions (trades, permits) |
Implementation Complexity | Low | Low | High |
Frequently Asked Questions
EIP-191 is a simple, flexible standard for signing data on Ethereum. It defines a structured format for signed messages, enabling secure off-chain data verification and preventing replay attacks across different contexts.
EIP-191 is an Ethereum Improvement Proposal that defines a standard format for signed data, allowing smart contracts and off-chain services to verify that a message was authorized by a specific Ethereum account. It works by defining a specific structure for the data to be signed, which includes a version byte, an optional domain separator, and the actual message data. This structure prevents a signature created for one purpose (e.g., a login) from being replayed for a different, unintended purpose (e.g., a token transfer). The most common version, 0x45 (E), prepends the string "\x19Ethereum Signed Message:\n" plus the message length, which is what personal signing methods like eth_sign use. The version 0x00 is used for structured data with a verifier address to define a specific context.
Get In Touch
today.
Our experts will offer a free quote and a 30min call to discuss your project.