Skip to content

Commit 09068e6

Browse files
committed
Merge branch 'eip1559'
2 parents 81e22c8 + 1b173f4 commit 09068e6

File tree

15 files changed

+2331
-360
lines changed

15 files changed

+2331
-360
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ customers cannot upgrade their bootloader, its changes are recorded separately.
1313
- Verifiable seed generation: when restoring from 12 or 18 recovery words, for the final word, restrict input to the valid candidate words which result in a valid checksum.
1414
For 24 words, this feature was already introduced in 9.4.0.
1515
- Bitcoin: don't warn about "unusual" sequence numbers in transactions anymore
16+
- Add EIP-1559 transaction support for Ethereum
1617

1718
### 9.15.0
1819
- Security bugfix: check index of an input's previous output to prevent the fee attack originally

CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ endif()
8888
#
8989
# Versions MUST contain three parts and start with lowercase 'v'.
9090
# Example 'v1.0.0'. They MUST not contain a pre-release label such as '-beta'.
91-
set(FIRMWARE_VERSION "v9.15.0")
92-
set(FIRMWARE_BTC_ONLY_VERSION "v9.15.0")
91+
set(FIRMWARE_VERSION "v9.16.0")
92+
set(FIRMWARE_BTC_ONLY_VERSION "v9.16.0")
9393
set(BOOTLOADER_VERSION "v1.0.5")
9494

9595
find_package(PythonInterp 3.6 REQUIRED)

messages/eth.proto

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ message ETHPubRequest {
4242
uint64 chain_id = 6;
4343
}
4444

45+
// TX payload for "legacy" (EIP-155) transactions: https://eips.ethereum.org/EIPS/eip-155
4546
message ETHSignRequest {
4647
// Deprecated: use chain_id instead.
4748
ETHCoin coin = 1;
@@ -57,6 +58,20 @@ message ETHSignRequest {
5758
uint64 chain_id = 10;
5859
}
5960

61+
// TX payload for an EIP-1559 (type 2) transaction: https://eips.ethereum.org/EIPS/eip-1559
62+
message ETHSignEIP1559Request {
63+
uint64 chain_id = 1;
64+
repeated uint32 keypath = 2;
65+
bytes nonce = 3; // smallest big endian serialization, max. 16 bytes
66+
bytes max_priority_fee_per_gas = 4; // smallest big endian serialization, max. 16 bytes
67+
bytes max_fee_per_gas = 5; // smallest big endian serialization, max. 16 bytes
68+
bytes gas_limit = 6; // smallest big endian serialization, max. 16 bytes
69+
bytes recipient = 7; // 20 byte recipient
70+
bytes value = 8; // smallest big endian serialization, max. 32 bytes
71+
bytes data = 9;
72+
AntiKleptoHostNonceCommitment host_nonce_commitment = 10;
73+
}
74+
6075
message ETHSignMessageRequest {
6176
// Deprecated: use chain_id instead.
6277
ETHCoin coin = 1;
@@ -130,6 +145,7 @@ message ETHRequest {
130145
AntiKleptoSignatureRequest antiklepto_signature = 4;
131146
ETHSignTypedMessageRequest sign_typed_msg = 5;
132147
ETHTypedMessageValueRequest typed_msg_value = 6;
148+
ETHSignEIP1559Request sign_eip1559 = 7;
133149
}
134150
}
135151

py/bitbox02/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Changelog
22

3+
## [Unreleased]
4+
- Accept EIP1559 transactions in `eth_sign()` - requires BitBox02 firmware v9.16.0
5+
36
## 6.2.0
47
- btc_sign: allow displaying BTC values in the 'sat' unit
58
- require hidapi 0.14.0 to fix a bug on macOS 13.3 which lists two BitBox02s instead of one

py/bitbox02/bitbox02/bitbox02/bitbox02.py

Lines changed: 66 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -757,28 +757,17 @@ def eth_sign(self, transaction: bytes, keypath: Sequence[int], chain_id: int = 1
757757
"""
758758
transaction should be given as a full rlp encoded eth transaction.
759759
"""
760-
nonce, gas_price, gas_limit, recipient, value, data, _, _, _ = rlp.decode(transaction)
761-
request = eth.ETHRequest()
762-
# pylint: disable=no-member
763-
request.sign.CopyFrom(
764-
eth.ETHSignRequest(
765-
coin=self._eth_coin(chain_id),
766-
chain_id=chain_id,
767-
keypath=keypath,
768-
nonce=nonce,
769-
gas_price=gas_price,
770-
gas_limit=gas_limit,
771-
recipient=recipient,
772-
value=value,
773-
data=data,
774-
)
775-
)
760+
is_eip1559 = transaction.startswith(b"\x02")
776761

777-
supports_antiklepto = self.version >= semver.VersionInfo(9, 5, 0)
778-
if supports_antiklepto:
762+
def handle_antiklepto(request: eth.ETHRequest) -> bytes:
779763
host_nonce = os.urandom(32)
764+
if is_eip1559:
765+
request.sign_eip1559.host_nonce_commitment.commitment = antiklepto_host_commit(
766+
host_nonce
767+
)
768+
else:
769+
request.sign.host_nonce_commitment.commitment = antiklepto_host_commit(host_nonce)
780770

781-
request.sign.host_nonce_commitment.commitment = antiklepto_host_commit(host_nonce)
782771
signer_commitment = self._eth_msg_query(
783772
request, expected_response="antiklepto_signer_commitment"
784773
).antiklepto_signer_commitment.commitment
@@ -796,6 +785,64 @@ def eth_sign(self, transaction: bytes, keypath: Sequence[int], chain_id: int = 1
796785

797786
return signature
798787

788+
if is_eip1559:
789+
self._require_atleast(semver.VersionInfo(9, 16, 0))
790+
(
791+
decoded_chain_id,
792+
nonce,
793+
priority_fee,
794+
max_fee,
795+
gas_limit,
796+
recipient,
797+
value,
798+
data,
799+
_,
800+
_,
801+
_,
802+
) = rlp.decode(transaction[1:])
803+
decoded_chain_id_int = int.from_bytes(decoded_chain_id, byteorder="big")
804+
if decoded_chain_id_int != chain_id:
805+
raise Exception(
806+
f"chainID argument ({chain_id}) does not match chainID encoded in transaction ({decoded_chain_id_int})"
807+
)
808+
request = eth.ETHRequest()
809+
# pylint: disable=no-member
810+
request.sign_eip1559.CopyFrom(
811+
eth.ETHSignEIP1559Request(
812+
chain_id=chain_id,
813+
keypath=keypath,
814+
nonce=nonce,
815+
max_priority_fee_per_gas=priority_fee,
816+
max_fee_per_gas=max_fee,
817+
gas_limit=gas_limit,
818+
recipient=recipient,
819+
value=value,
820+
data=data,
821+
)
822+
)
823+
return handle_antiklepto(request)
824+
825+
nonce, gas_price, gas_limit, recipient, value, data, _, _, _ = rlp.decode(transaction)
826+
request = eth.ETHRequest()
827+
# pylint: disable=no-member
828+
request.sign.CopyFrom(
829+
eth.ETHSignRequest(
830+
coin=self._eth_coin(chain_id),
831+
chain_id=chain_id,
832+
keypath=keypath,
833+
nonce=nonce,
834+
gas_price=gas_price,
835+
gas_limit=gas_limit,
836+
recipient=recipient,
837+
value=value,
838+
data=data,
839+
)
840+
)
841+
842+
supports_antiklepto = self.version >= semver.VersionInfo(9, 5, 0)
843+
if supports_antiklepto:
844+
return handle_antiklepto(request)
845+
799846
return self._eth_msg_query(request, expected_response="sign").sign.signature
800847

801848
def eth_sign_msg(self, msg: bytes, keypath: Sequence[int], chain_id: int = 1) -> bytes:

py/bitbox02/bitbox02/communication/generated/btc_pb2.pyi

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ class BTCScriptConfig(google.protobuf.message.Message):
104104
threshold: builtins.int
105105
@property
106106
def xpubs(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[common_pb2.XPub]:
107-
"""xpubs are acount-level xpubs. Addresses are going to be derived from it using: m/<change>/<receive>.
107+
"""xpubs are acount-level xpubs. Addresses are going to be derived from it using: `m/<change>/<receive>`.
108108
The number of xpubs defines the number of cosigners.
109109
"""
110110
pass
@@ -460,7 +460,9 @@ class BTCScriptConfigRegistration(google.protobuf.message.Message):
460460
@property
461461
def script_config(self) -> global___BTCScriptConfig: ...
462462
@property
463-
def keypath(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.int]: ...
463+
def keypath(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.int]:
464+
"""Unused for policy registrations."""
465+
pass
464466
def __init__(self,
465467
*,
466468
coin: global___BTCCoin.ValueType = ...,

0 commit comments

Comments
 (0)