Skip to content

Instantly share code, notes, and snippets.

@pcaversaccio
Created July 17, 2023 15:41
Show Gist options
  • Save pcaversaccio/49adaf6ad482a59225c3cabb18e2acc3 to your computer and use it in GitHub Desktop.
Save pcaversaccio/49adaf6ad482a59225c3cabb18e2acc3 to your computer and use it in GitHub Desktop.
A Vyper utility function that transforms a standard signature into an EIP-2098 (https://eips.ethereum.org/EIPS/eip-2098) compliant signature.
# @version ^0.3.9
@internal
@pure
def _to_2098_format(signature: Bytes[65]) -> Bytes[64]:
"""
@dev Transforms a standard signature into an EIP-2098
(https://eips.ethereum.org/EIPS/eip-2098) compliant
signature.
@param signature The secp256k1 64/65-bytes signature.
@return Bytes The 64-bytes EIP-2098 compliant signature.
"""
assert len(signature) == 65, "ERC-2098: invalid signature length"
assert (convert(slice(signature, 32, 1), uint256) >> 7) != 1, "ERC-2098: invalid signature `s` value"
short: Bytes[64] = slice(signature, 0, 64)
parity_bit: uint8 = convert((convert(slice(short, 32, 1), uint256) | ((convert(slice(signature, 64, 1), uint256) % 27) << 7)), uint8)
return concat(slice(short, 0, 32), convert(parity_bit, bytes1), slice(short, 33, 31))
@external
@view
def test_to_2098_format():
"""
@dev Since Foundry writes tests in Solidity, I can write
tests in Vyper :). Use Titanoboa (https://github.com/vyperlang/titanoboa)
to run it:
```console
>>> import boa
>>> erc2098 = boa.load("./ERC2098.vy")
>>> erc2098.test_to_2098_format()
```
@notice The two test cases are from here:
https://eips.ethereum.org/EIPS/eip-2098#test-cases.
"""
r_1: bytes32 = 0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b90
s_1: bytes32 = 0x7e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064
v_1: uint8 = 27
y_parity_and_s_1: bytes32 = 0x7e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064
r_2: bytes32 = 0x9328da16089fcba9bececa81663203989f2df5fe1faa6291a45381c81bd17f76
s_2: bytes32 = 0x139c6d6b623b42da56557e5e734a43dc83345ddfadec52cbe24d0cc64f550793
v_2: uint8 = 28
y_parity_and_s_2: bytes32 = 0x939c6d6b623b42da56557e5e734a43dc83345ddfadec52cbe24d0cc64f550793
signature_1: Bytes[65] = concat(r_1, s_1, convert(v_1, bytes1))
signature_2: Bytes[65] = concat(r_2, s_2, convert(v_2, bytes1))
compact_signature_1: Bytes[64] = concat(r_1, y_parity_and_s_1)
compact_signature_2: Bytes[64] = concat(r_2, y_parity_and_s_2)
assert self._to_2098_format(signature_1) == compact_signature_1, "ERC-2098: invalid signature"
assert self._to_2098_format(signature_2) == compact_signature_2, "ERC-2098: invalid signature"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment