EIP 191: Signed Data Standard
| Author | Martin Holst Swende, Nick Johnson |
|---|---|
| Status | Draft |
| Type | Standards Track |
| Category | ERC |
| Created | 2016-01-20 |
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 calledRLPdata),r,sandv. If there are no syntactical constraints onsigned_data, this means thatRLPdatacan be used as a syntactically validpresignedtransaction. - Multisignature wallets have also had the problem that a
presignedtransaction has not been tied to a particularvalidator, i.e a specific wallet. Example:- Users
A,BandChave the2/3-walletX - Users
A,BandDhave the2/3-walletY - User
AandBsubmitespresignedtransaction toX. - Attacker can now reuse their presigned transactions to
X, and submit toY.
- Users
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
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)
public
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
Copyright and related rights waived via CC0.