forked from DecentralizedClimateFoundation/DCIPs
139 lines
4.5 KiB
Markdown
139 lines
4.5 KiB
Markdown
---
|
|
eip: 2098
|
|
title: Compact Signature Representation
|
|
description: A compact representation of an Ethereum Signature.
|
|
status: Final
|
|
type: Standards Track
|
|
category: ERC
|
|
author: Richard Moore (@ricmoo), Nick Johnson <nick@ethereum.org>
|
|
discussions-to: https://github.com/ethereum/EIPs/issues/2440
|
|
created: 2019-03-14
|
|
requires: 2
|
|
---
|
|
|
|
|
|
## Abstract
|
|
|
|
The secp256k1 curve permits the computation of the public key of signed
|
|
digest when coupled with a signature, which is used implicitly to
|
|
establish the origin of a transaction from an Externally Owned Account
|
|
as well as on-chain in EVM contracts for example, in meta-transactions and
|
|
multi-sig contracts.
|
|
|
|
Currently signatures require 65 bytes to represent, which when aligned
|
|
to 256-bit words, requires 96 bytes (with 31 zero bytes injected). The
|
|
yParity in RLP-encoded transactions also require (on average) 1.5 bytes.
|
|
With compact signatures, this can be reduced to 64 bytes, which remains 64
|
|
bytes when word-aligned, and in the case of RLP-encoded transactions
|
|
saves the 1.5 bytes required for the yParity.
|
|
|
|
## Motivation
|
|
|
|
The motivations for a compact representation are to simplify handling
|
|
transactions in client code, reduce gas costs and reduce transaction sizes.
|
|
|
|
|
|
## Specification
|
|
|
|
A secp256k1 signature is made up of 3 parameters, `r`, `s` and `yParity`.
|
|
The `r` represents the `x` component on the curve (from which the `y` can be
|
|
computed), and the `s` represents the challenge solution for signing by a
|
|
private key. Due to the symmetric nature of an elliptic curve, a `yParity`
|
|
is required, which indicates which of the 2 possible solutions was intended,
|
|
by indicating its parity (odd-ness).
|
|
|
|
Two key observations are required to create a compact representation.
|
|
|
|
First, the `yParity` parameter is always either 0 or 1 (canonically the values
|
|
used have historically been 27 and 28, as these values didn't collide with other
|
|
binary prefixes used in Bitcoin).
|
|
|
|
Second, the top bit of the `s` parameters is **always** 0, due to the use of
|
|
canonical signatures which flip the solution parity to prevent negative values,
|
|
which was introduced as [a constraint in Homestead](./eip-2.md).
|
|
|
|
So, we can hijack the top bit in the `s` parameter to store the value of
|
|
`yParity`, resulting in:
|
|
|
|
```
|
|
[256-bit r value][1-bit yParity value][255-bit s value]
|
|
```
|
|
|
|
|
|
### Example Implementation In Python
|
|
|
|
```python
|
|
# Assume yParity is 0 or 1, normalized from the canonical 27 or 28
|
|
def to_compact(r, s, yParity):
|
|
return {
|
|
"r": r,
|
|
"yParityAndS": (yParity << 255) | s
|
|
}
|
|
|
|
def to_canonical(r, yParityAndS):
|
|
return {
|
|
"r": r,
|
|
"s": yParityAndS & ((1 << 255) - 1),
|
|
"yParity": (yParityAndS >> 255)
|
|
}
|
|
```
|
|
|
|
|
|
## Rationale
|
|
|
|
The compact representation proposed is simple to both compose and decompose
|
|
in clients and in Solidity, so that it can be easily (and intuitively) supported,
|
|
while reducing transaction sizes and gas costs.
|
|
|
|
|
|
## Backwards Compatibility
|
|
|
|
The Compact Representation does not collide with canonical signature as
|
|
it uses 2 parameters (r, yParityAndS) and is 64 bytes long while canonical
|
|
signatures involve 3 separate parameters (r, s, yParity) and are 65 bytes long.
|
|
|
|
|
|
## Test Cases
|
|
|
|
```
|
|
Private Key: 0x1234567890123456789012345678901234567890123456789012345678901234
|
|
Message: "Hello World"
|
|
Signature:
|
|
r: 0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b90
|
|
s: 0x7e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064
|
|
v: 27
|
|
Compact Signature:
|
|
r: 0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b90
|
|
yParityAndS: 0x7e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064
|
|
```
|
|
|
|
```
|
|
Private Key: 0x1234567890123456789012345678901234567890123456789012345678901234
|
|
Message: "It's a small(er) world"
|
|
Signature:
|
|
r: 0x9328da16089fcba9bececa81663203989f2df5fe1faa6291a45381c81bd17f76
|
|
s: 0x139c6d6b623b42da56557e5e734a43dc83345ddfadec52cbe24d0cc64f550793
|
|
v: 28
|
|
Compact Signature:
|
|
r: 0x9328da16089fcba9bececa81663203989f2df5fe1faa6291a45381c81bd17f76
|
|
yParityAndS: 0x939c6d6b623b42da56557e5e734a43dc83345ddfadec52cbe24d0cc64f550793
|
|
```
|
|
|
|
|
|
## Reference Implementation
|
|
|
|
The ethers.js library [supports this in v5](https://github.com/ethers-io/ethers.js/blob/ethers-v5-beta/packages/bytes/src.ts/index.ts#L323)
|
|
as an unofficial property of split signatures (i.e. `sig._vs`), but should be
|
|
considered an internal property that may change at discretion of the community
|
|
and any changes to this EIP.
|
|
|
|
|
|
## Security Considerations
|
|
|
|
There are no additional security concerns introduced by this EIP.
|
|
|
|
|
|
## Copyright
|
|
|
|
Copyright and related rights waived via [CC0](../LICENSE.md).
|