Recoverable ECDSA signatures can flip s and v while remaining valid, so they can be compressed to 64 bytes by restricting v.
ECDSA signatures are often encoded with three parameters: v, r, and s.
In the Solidity ABI encoding, this is 96 bytes.
By eliminating the degree of freedom, v, the encoded size of a recoverable signature can be reduced to 64 bytes.
Additionally, such signatures are not malleable.
Smart contracts accepting bound signatures MUST supply 27 for v.
address signer = ecrecover(digest, 27, r, s);
require(signer != address(0));
ECDSA signatures MUST be bound before supplied to such contracts.
const SECP256K1_N: bigint = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n
function bind(sig: Signature, v: 27 | 28 = 27): Signature {
if (sig.v === v) {
return sig
}
const s = SECP256K1_N - sig.s
return new Signature(sig.r, s, v)
}
Another signature compression approach, ERC-2098, stores the y-parity bit in the most-significant bit of the low s.
Bound signatures are preferable because they are valid inputs to the ecrecover precompile.
They require less gas because they do not need to be unpacked by the smart contract.
27 was chosen over 28 to make the y-parity falsy.
Bound signatures are compatible with ecrecover if 27 is supplied for the v parameter.
They cannot be used for transaction signatures because they permit high s, in violation of EIP-2.
| Signer | Digest | r |
s |
|---|---|---|---|
0x4a6f6B9fF1fc974096f9063a45Fd12bD5B928AD1 |
0xb0922c37cafd247fe3ada4eb1d1e3735b7d2837437c1178e9af120d535214270 |
0xdb7f75635124c807ec1f8b03e34cd76b633dc3a189e3c85fc5aee7e7d71df38c |
0x5f1e6c6edf21cacfc2acba2815b253b9048b894eec5aaf70343389bb596c48bc |
0x4a6f6B9fF1fc974096f9063a45Fd12bD5B928AD1 |
0xd92ff06caae7253883627416a425414d79e9003b91d6208add30e73735ef13c3 |
0xaa40efd534ac7f96b85babd7df9228fa131e8523115ca1ebc025698c37f3867d |
0xa4b8d3c650fe62e46a563aed681bfdd44d50452fa7712bd139f2bfba3aed59c9 |
0x6B93E3bB9C0780C0f9042346Ffc379530a5882c1 |
0xfa75eba87f076cf22489da7c53a651bb3869473f78d09d4814afb7ab2d54ed45 |
0xaf4a877600ab6d14ebac626830cf1063d624487932b3cc73a7cd98ae7fbf337f |
0xbc41d29acfcd3a1e7b5cb2dde1b85fe8882739312639b5f16d476a87584c040f |
pragma solidity ^0.8.30;
library BoundSignatures {
function recover(bytes32 digest, bytes32 r, bytes32 s) internal pure returns (address signer) {
signer = ecrecover(digest, 27, r, s);
require(signer != address(0));
}
}
Bound signatures are recoverable and not malleable.
Copyright and related rights waived via CC0.