EIP191 - Signed Data Standard

# 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 submites presigned transaction 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>.

Version 0 has <20 byte address> for the version specific data, and the address is the intended validator. In the case of a Multisig wallet, that is the wallet's own address .

The initial 0x19 byte is intended to ensure that the signed_data is not valid RLP (opens new window)

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 ERC-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 byte EIP Description
0x00 191 Data with intended validator
0x01 712 Structured data
0x45 191 personal_sign messages

# Example

The following snippet has been written in Solidity 0.5.0.

function submitTransactionPreSigned(address destination, uint value, bytes data, uint nonce, uint8 v, bytes32 r, bytes32 s)
    returns (bytes32 transactionHash)
    // Arguments when calculating hash to validate
    // 1: byte(0x19) - the initial 0x19 byte
    // 2: byte(0) - the version byte
    // 3: this - the validator address
    // 4-7 : Application specific data
    transactionHash = keccak256(abi.encodePacked(byte(0x19),byte(0),address(this),destination, value, data, nonce));
    sender = ecrecover(transactionHash, v, r, s);
    // ...

Copyright and related rights waived via CC0 (opens new window).

▲ Powered by Vercel