From d5e48aea808568d5202725f6996038b19cfc36a9 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Mon, 11 Mar 2024 15:37:04 +0100 Subject: [PATCH 1/4] Removed EIP-155 calculation on V for EIP-1559 ecrecover in client --- .../src/ledger_app_clients/ethereum/utils.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/client/src/ledger_app_clients/ethereum/utils.py b/client/src/ledger_app_clients/ethereum/utils.py index 2b50fe551..196d01152 100644 --- a/client/src/ledger_app_clients/ethereum/utils.py +++ b/client/src/ledger_app_clients/ethereum/utils.py @@ -23,16 +23,16 @@ def recover_transaction(tx_params, vrs: tuple) -> bytes: if raw_tx[0] in [0x01, 0x02]: prefix = raw_tx[:1] raw_tx = raw_tx[len(prefix):] - # v is returned on one byte only so it might have overflowed - # in that case, we will reconstruct it to its full value - if "chainId" in tx_params: - trunc_chain_id = tx_params["chainId"] - while trunc_chain_id.bit_length() > 32: - trunc_chain_id >>= 8 - target = tx_params["chainId"] * 2 + 35 - trunc_target = trunc_chain_id * 2 + 35 - diff = vrs[0][0] - (trunc_target & 0xff) - vrs = (target + diff, vrs[1], vrs[2]) + else: + # v is returned on one byte only so it might have overflowed + # in that case, we will reconstruct it to its full value + if "chainId" in tx_params: + trunc_chain_id = tx_params["chainId"] + while trunc_chain_id.bit_length() > 32: + trunc_chain_id >>= 8 + trunc_target = trunc_chain_id * 2 + 35 + parity = int.from_bytes(vrs[0], "big") - (trunc_target & 0xff) + vrs = (parity + tx_params["chainId"] * 2 + 35, vrs[1], vrs[2]) decoded = rlp.decode(raw_tx) reencoded = rlp.encode(decoded[:-3] + list(vrs)) addr = Account.recover_transaction(prefix + reencoded) From 1783900cb1176d4a10b87bd7e7c8a52c74a3035c Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Tue, 12 Mar 2024 17:22:00 +0100 Subject: [PATCH 2/4] Fix EIP-155 V reconstruction for ecrecover in client --- .../src/ledger_app_clients/ethereum/utils.py | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/client/src/ledger_app_clients/ethereum/utils.py b/client/src/ledger_app_clients/ethereum/utils.py index 196d01152..b5cc9efaa 100644 --- a/client/src/ledger_app_clients/ethereum/utils.py +++ b/client/src/ledger_app_clients/ethereum/utils.py @@ -24,15 +24,31 @@ def recover_transaction(tx_params, vrs: tuple) -> bytes: prefix = raw_tx[:1] raw_tx = raw_tx[len(prefix):] else: - # v is returned on one byte only so it might have overflowed - # in that case, we will reconstruct it to its full value if "chainId" in tx_params: + # v is returned on one byte only so it might have overflowed + # in that case, we will reconstruct it to its full value trunc_chain_id = tx_params["chainId"] while trunc_chain_id.bit_length() > 32: trunc_chain_id >>= 8 + trunc_target = trunc_chain_id * 2 + 35 - parity = int.from_bytes(vrs[0], "big") - (trunc_target & 0xff) - vrs = (parity + tx_params["chainId"] * 2 + 35, vrs[1], vrs[2]) + trunc_v = int.from_bytes(vrs[0], "big") + + if (trunc_target & 0xff) == trunc_v: + parity = 0 + elif ((trunc_target + 1) & 0xff) == trunc_v: + parity = 1 + else: + # should have matched with a previous if + assert False + + # https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md + full_v = parity + tx_params["chainId"] * 2 + 35 + # 9 bytes would be big enough even for the biggest chain ID + vrs = (int(full_v).to_bytes(9, "big"), vrs[1], vrs[2]) + else: + # Pre EIP-155 TX + assert False decoded = rlp.decode(raw_tx) reencoded = rlp.encode(decoded[:-3] + list(vrs)) addr = Account.recover_transaction(prefix + reencoded) From b71e591da1f6cb426445147509dce32dae763cbb Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Tue, 12 Mar 2024 17:22:42 +0100 Subject: [PATCH 3/4] Normalize VRS for eth_account requirements in client --- client/src/ledger_app_clients/ethereum/utils.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/client/src/ledger_app_clients/ethereum/utils.py b/client/src/ledger_app_clients/ethereum/utils.py index b5cc9efaa..0fa350840 100644 --- a/client/src/ledger_app_clients/ethereum/utils.py +++ b/client/src/ledger_app_clients/ethereum/utils.py @@ -3,6 +3,14 @@ import rlp +# eth_account requires it for some reason +def normalize_vrs(vrs: tuple) -> tuple: + vrs_l = list() + for elem in vrs: + vrs_l.append(elem.lstrip(b'\x00')) + return tuple(vrs_l) + + def get_selector_from_data(data: str) -> bytes: raw_data = bytes.fromhex(data[2:]) return raw_data[:4] @@ -13,7 +21,7 @@ def recover_message(msg, vrs: tuple) -> bytes: smsg = encode_typed_data(full_message=msg) else: # EIP-191 smsg = encode_defunct(primitive=msg) - addr = Account.recover_message(smsg, vrs) + addr = Account.recover_message(smsg, normalize_vrs(vrs)) return bytes.fromhex(addr[2:]) @@ -50,6 +58,6 @@ def recover_transaction(tx_params, vrs: tuple) -> bytes: # Pre EIP-155 TX assert False decoded = rlp.decode(raw_tx) - reencoded = rlp.encode(decoded[:-3] + list(vrs)) + reencoded = rlp.encode(decoded[:-3] + list(normalize_vrs(vrs))) addr = Account.recover_transaction(prefix + reencoded) return bytes.fromhex(addr[2:]) From d1ea89b2834652277b60d1684c066210245d9ccf Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Tue, 12 Mar 2024 17:52:11 +0100 Subject: [PATCH 4/4] Updated client changelog --- client/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/client/CHANGELOG.md b/client/CHANGELOG.md index 094bcd627..00fc82ea4 100644 --- a/client/CHANGELOG.md +++ b/client/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.3.1] - 2024-03-12 + +### Fixed + +- `recover_transaction` & `recover_message` util functions + ## [0.3.0] - 2024-02-13 ### Added