HomeEIPs
EIPsERC-191
ERC-191

Signed Data Standard

FinalStandards Track: ERC
Created: 2016-01-20
Martin Holst Swende (@holiman), Nick Johnson <arachnid@notdot.net>
DiscussionsOriginal linkEdit
1 min read

ERC-191 proposes a specification for handling signed data in Ethereum contracts. The motivation behind this proposal is to address the issue of presigned transactions not being tied to a specific validator, which can lead to security vulnerabilities. The proposed format for signed data includes an initial 0x19 byte to ensure that it is not a valid RLP, and for a single byte whose value is in the [0x00, 0x7f] range, that byte is its own RLP encoding. This means that any signed data cannot be one RLP-structure, but a 1-byte RLP payload followed by something else. Additionally, 0x19 has been chosen because it is prepended before hashing in personal_sign, making it possible to extend the scheme by defining a version 0x45 (E) to handle these kinds of signatures. The proposal also includes a registry of version bytes, including 0x00 for the initial version, 0x01 for data with intended validator, and 0x45 for personal_sign messages. Overall, ERC-191 aims to provide a standardized approach for handling signed data in Ethereum contracts to improve security and prevent potential vulnerabilities.

Video
Anyone may contribute to propose contents.
Go propose
Original

Abstract

This ERC proposes a specification about how to handle signed data in Ethereum contracts.

Motivation

Several multisignature wallet implementations have been created which accepts presigned transactions. A presigned transaction is a chunk of binary signed_data, along with signature (r, s and v). The interpretation of the signed_data has not been specified, leading to several problems:

  • Standard Ethereum transactions can be submitted as signed_data. An Ethereum transaction can be unpacked, into the following components: RLP<nonce, gasPrice, startGas, to, value, data> (hereby called RLPdata), r, s and v. If there are no syntactical constraints on signed_data, this means that RLPdata can be used as a syntactically valid presigned transaction.
  • Multisignature wallets have also had the problem that a presigned transaction has not been tied to a particular validator, i.e a specific wallet. Example:
    1. Users A, B and C have the 2/3-wallet X
    2. Users A, B and D have the 2/3-wallet Y
    3. User A and B submit presigned transactions to X.
    4. Attacker can now reuse their presigned transactions to X, and submit to Y.

Specification

We propose the following format for signed_data

0x19 <1 byte version> <version specific data> <data to sign>.

The initial 0x19 byte is intended to ensure that the signed_data is not valid RLP.

For a single byte whose value is in the [0x00, 0x7f] range, that byte is its own RLP encoding.

That means that any signed_data cannot be one RLP-structure, but a 1-byte RLP payload followed by something else. Thus, any EIP-191 signed_data can never be an Ethereum transaction.

Additionally, 0x19 has been chosen because since ethereum/go-ethereum#2940 , the following is prepended before hashing in personal_sign:

"\x19Ethereum Signed Message:\n" + len(message).

Using 0x19 thus makes it possible to extend the scheme by defining a version 0x45 (E) to handle these kinds of signatures.

Registry of version bytes

Version byteEIPDescription
0x00191Data with intended validator
0x01712Structured data
0x45191personal_sign messages

Version 0x00

0x19 <0x00> <intended validator address> <data to sign>

The version 0x00 has <intended validator address> for the version specific data. In the case of a Multisig wallet that perform an execution based on a passed signature, the validator address is the address of the Multisig itself. The data to sign could be any arbitrary data.

Version 0x01

The version 0x01 is for structured data as defined in EIP-712

Version 0x45 (E)

0x19 <0x45 (E)> <thereum Signed Message:\n" + len(message)> <data to sign>

The version 0x45 (E) has <thereum Signed Message:\n" + len(message)> for the version-specific data. The data to sign can be any arbitrary data.

NB: The E in Ethereum Signed Message refers to the version byte 0x45. The character E is 0x45 in hexadecimal which makes the remainder, thereum Signed Message:\n + len(message), the version-specific data.

Example

The following snippets has been written in Solidity 0.8.0.

Version 0x00

function signatureBasedExecution(address target, uint256 nonce, bytes memory payload, uint8 v, bytes32 r, bytes32 s) public payable { // Arguments when calculating hash to validate // 1: byte(0x19) - the initial 0x19 byte // 2: byte(0) - the version byte // 3: address(this) - the validator address // 4-6 : Application specific data bytes32 hash = keccak256(abi.encodePacked(byte(0x19), byte(0), address(this), msg.value, nonce, payload)); // recovering the signer from the hash and the signature addressRecovered = ecrecover(hash, v, r, s); // logic of the wallet // if (addressRecovered == owner) executeOnTarget(target, payload); }

Copyright and related rights waived via CC0.

Further reading
Anyone may contribute to propose contents.
Go propose
Adopted by projects
Anyone may contribute to propose contents.
Go propose

Not miss a beat of EIPs' update?

Subscribe EIPs Fun to receive the latest updates of EIPs Good for Buidlers to follow up.

View all
Serve EIP builders, scale Ethereum.
Resources
GitHub
Supported by