Skip to content

Commit

Permalink
Merge branch 'ethchains'
Browse files Browse the repository at this point in the history
  • Loading branch information
benma committed Feb 28, 2022
2 parents 93d4e4f + 3140762 commit 234cf09
Show file tree
Hide file tree
Showing 14 changed files with 188 additions and 59 deletions.
9 changes: 9 additions & 0 deletions messages/eth.proto
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ enum ETHCoin {

message ETHPubRequest {
repeated uint32 keypath = 1;
// Deprecated: use chain_id instead.
ETHCoin coin = 2;
enum OutputType {
ADDRESS = 0;
Expand All @@ -34,9 +35,12 @@ message ETHPubRequest {
OutputType output_type = 3;
bool display = 4;
bytes contract_address = 5;
// If non-zero, `coin` is ignored and `chain_id` is used to identify the network.
uint64 chain_id = 6;
}

message ETHSignRequest {
// Deprecated: use chain_id instead.
ETHCoin coin = 1;
repeated uint32 keypath = 2;
bytes nonce = 3; // smallest big endian serialization, max. 16 bytes
Expand All @@ -46,13 +50,18 @@ message ETHSignRequest {
bytes value = 7; // smallest big endian serialization, max. 32 bytes
bytes data = 8;
AntiKleptoHostNonceCommitment host_nonce_commitment = 9;
// If non-zero, `coin` is ignored and `chain_id` is used to identify the network.
uint64 chain_id = 10;
}

message ETHSignMessageRequest {
// Deprecated: use chain_id instead.
ETHCoin coin = 1;
repeated uint32 keypath = 2;
bytes msg = 3;
AntiKleptoHostNonceCommitment host_nonce_commitment = 4;
// If non-zero, `coin` is ignored and `chain_id` is used to identify the network.
uint64 chain_id = 5;
}

message ETHSignResponse {
Expand Down
1 change: 1 addition & 0 deletions py/bitbox02/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
- Offset the recoverable ID by 27 in the signature returned by `eth_sign_msg()`.
- Rename `BTCOutputExternal.hash` to `BTCOutputExternal.payload`.
- Support P2TR (taproot) receive addresses and transaction inputs
- `eth_pub()`, `eth_sign()` and `eth_sign_msg()` now take the network chain ID instead of a ETHCoin enum value for network identification
32 changes: 22 additions & 10 deletions py/bitbox02/bitbox02/bitbox02/bitbox02.py
Original file line number Diff line number Diff line change
Expand Up @@ -716,10 +716,20 @@ def _eth_msg_query(
)
return eth_response

def _eth_coin(self, chain_id: int) -> "eth.ETHCoin.V":
"""Returns the deprecated `coin` enum value for a given chain_id. Only ETH, Ropsten and Rinkeby are converted, as these were the only supported networks up to v9.10.0. With v9.10.0, the chain ID is passed directly, and the `coin` field is ignored."""
if self.version < semver.VersionInfo(9, 10, 0):
return {
1: eth.ETHCoin.ETH,
3: eth.ETHCoin.RopstenETH,
4: eth.ETHCoin.RinkebyETH,
}[chain_id]
return eth.ETHCoin.ETH

def eth_pub(
self,
keypath: Sequence[int],
coin: "eth.ETHCoin.V" = eth.ETH,
chain_id: int = 1,
output_type: "eth.ETHPubRequest.OutputType.V" = eth.ETHPubRequest.ADDRESS,
display: bool = True,
contract_address: bytes = b"",
Expand All @@ -732,7 +742,8 @@ def eth_pub(
request = eth.ETHRequest()
request.pub.CopyFrom(
eth.ETHPubRequest(
coin=coin,
coin=self._eth_coin(chain_id),
chain_id=chain_id,
keypath=keypath,
output_type=output_type,
display=display,
Expand All @@ -741,9 +752,7 @@ def eth_pub(
)
return self._eth_msg_query(request, expected_response="pub").pub.pub

def eth_sign(
self, transaction: bytes, keypath: Sequence[int], coin: "eth.ETHCoin.V" = eth.ETH
) -> bytes:
def eth_sign(self, transaction: bytes, keypath: Sequence[int], chain_id: int = 1) -> bytes:
"""
transaction should be given as a full rlp encoded eth transaction.
"""
Expand All @@ -752,7 +761,8 @@ def eth_sign(
# pylint: disable=no-member
request.sign.CopyFrom(
eth.ETHSignRequest(
coin=coin,
coin=self._eth_coin(chain_id),
chain_id=chain_id,
keypath=keypath,
nonce=nonce,
gas_price=gas_price,
Expand Down Expand Up @@ -787,9 +797,7 @@ def eth_sign(

return self._eth_msg_query(request, expected_response="sign").sign.signature

def eth_sign_msg(
self, msg: bytes, keypath: Sequence[int], coin: "eth.ETHCoin.V" = eth.ETH
) -> bytes:
def eth_sign_msg(self, msg: bytes, keypath: Sequence[int], chain_id: int = 1) -> bytes:
"""
Signs message, the msg will be prefixed with "\x19Ethereum message\n" + len(msg) in the
hardware. 27 is added to the recID to denote an uncompressed pubkey.
Expand All @@ -804,7 +812,11 @@ def format_as_uncompressed(sig: bytes) -> bytes:

request = eth.ETHRequest()
# pylint: disable=no-member
request.sign_msg.CopyFrom(eth.ETHSignMessageRequest(coin=coin, keypath=keypath, msg=msg))
request.sign_msg.CopyFrom(
eth.ETHSignMessageRequest(
coin=self._eth_coin(chain_id), chain_id=chain_id, keypath=keypath, msg=msg
)
)

supports_antiklepto = self.version >= semver.VersionInfo(9, 5, 0)
if supports_antiklepto:
Expand Down
53 changes: 37 additions & 16 deletions py/bitbox02/bitbox02/communication/generated/eth_pb2.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 24 additions & 3 deletions py/bitbox02/bitbox02/communication/generated/eth_pb2.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,28 @@ class ETHPubRequest(google.protobuf.message.Message):
OUTPUT_TYPE_FIELD_NUMBER: builtins.int
DISPLAY_FIELD_NUMBER: builtins.int
CONTRACT_ADDRESS_FIELD_NUMBER: builtins.int
CHAIN_ID_FIELD_NUMBER: builtins.int
@property
def keypath(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.int]: ...
coin: global___ETHCoin.V = ...
"""Deprecated: use chain_id instead."""

output_type: global___ETHPubRequest.OutputType.V = ...
display: builtins.bool = ...
contract_address: builtins.bytes = ...
chain_id: builtins.int = ...
"""If non-zero, `coin` is ignored and `chain_id` is used to identify the network."""

def __init__(self,
*,
keypath : typing.Optional[typing.Iterable[builtins.int]] = ...,
coin : global___ETHCoin.V = ...,
output_type : global___ETHPubRequest.OutputType.V = ...,
display : builtins.bool = ...,
contract_address : builtins.bytes = ...,
chain_id : builtins.int = ...,
) -> None: ...
def ClearField(self, field_name: typing_extensions.Literal["coin",b"coin","contract_address",b"contract_address","display",b"display","keypath",b"keypath","output_type",b"output_type"]) -> None: ...
def ClearField(self, field_name: typing_extensions.Literal["chain_id",b"chain_id","coin",b"coin","contract_address",b"contract_address","display",b"display","keypath",b"keypath","output_type",b"output_type"]) -> None: ...
global___ETHPubRequest = ETHPubRequest

class ETHSignRequest(google.protobuf.message.Message):
Expand All @@ -77,7 +84,10 @@ class ETHSignRequest(google.protobuf.message.Message):
VALUE_FIELD_NUMBER: builtins.int
DATA_FIELD_NUMBER: builtins.int
HOST_NONCE_COMMITMENT_FIELD_NUMBER: builtins.int
CHAIN_ID_FIELD_NUMBER: builtins.int
coin: global___ETHCoin.V = ...
"""Deprecated: use chain_id instead."""

@property
def keypath(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.int]: ...
nonce: builtins.bytes = ...
Expand All @@ -98,6 +108,9 @@ class ETHSignRequest(google.protobuf.message.Message):
data: builtins.bytes = ...
@property
def host_nonce_commitment(self) -> antiklepto_pb2.AntiKleptoHostNonceCommitment: ...
chain_id: builtins.int = ...
"""If non-zero, `coin` is ignored and `chain_id` is used to identify the network."""

def __init__(self,
*,
coin : global___ETHCoin.V = ...,
Expand All @@ -109,9 +122,10 @@ class ETHSignRequest(google.protobuf.message.Message):
value : builtins.bytes = ...,
data : builtins.bytes = ...,
host_nonce_commitment : typing.Optional[antiklepto_pb2.AntiKleptoHostNonceCommitment] = ...,
chain_id : builtins.int = ...,
) -> None: ...
def HasField(self, field_name: typing_extensions.Literal["host_nonce_commitment",b"host_nonce_commitment"]) -> builtins.bool: ...
def ClearField(self, field_name: typing_extensions.Literal["coin",b"coin","data",b"data","gas_limit",b"gas_limit","gas_price",b"gas_price","host_nonce_commitment",b"host_nonce_commitment","keypath",b"keypath","nonce",b"nonce","recipient",b"recipient","value",b"value"]) -> None: ...
def ClearField(self, field_name: typing_extensions.Literal["chain_id",b"chain_id","coin",b"coin","data",b"data","gas_limit",b"gas_limit","gas_price",b"gas_price","host_nonce_commitment",b"host_nonce_commitment","keypath",b"keypath","nonce",b"nonce","recipient",b"recipient","value",b"value"]) -> None: ...
global___ETHSignRequest = ETHSignRequest

class ETHSignMessageRequest(google.protobuf.message.Message):
Expand All @@ -120,21 +134,28 @@ class ETHSignMessageRequest(google.protobuf.message.Message):
KEYPATH_FIELD_NUMBER: builtins.int
MSG_FIELD_NUMBER: builtins.int
HOST_NONCE_COMMITMENT_FIELD_NUMBER: builtins.int
CHAIN_ID_FIELD_NUMBER: builtins.int
coin: global___ETHCoin.V = ...
"""Deprecated: use chain_id instead."""

@property
def keypath(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.int]: ...
msg: builtins.bytes = ...
@property
def host_nonce_commitment(self) -> antiklepto_pb2.AntiKleptoHostNonceCommitment: ...
chain_id: builtins.int = ...
"""If non-zero, `coin` is ignored and `chain_id` is used to identify the network."""

def __init__(self,
*,
coin : global___ETHCoin.V = ...,
keypath : typing.Optional[typing.Iterable[builtins.int]] = ...,
msg : builtins.bytes = ...,
host_nonce_commitment : typing.Optional[antiklepto_pb2.AntiKleptoHostNonceCommitment] = ...,
chain_id : builtins.int = ...,
) -> None: ...
def HasField(self, field_name: typing_extensions.Literal["host_nonce_commitment",b"host_nonce_commitment"]) -> builtins.bool: ...
def ClearField(self, field_name: typing_extensions.Literal["coin",b"coin","host_nonce_commitment",b"host_nonce_commitment","keypath",b"keypath","msg",b"msg"]) -> None: ...
def ClearField(self, field_name: typing_extensions.Literal["chain_id",b"chain_id","coin",b"coin","host_nonce_commitment",b"host_nonce_commitment","keypath",b"keypath","msg",b"msg"]) -> None: ...
global___ETHSignMessageRequest = ETHSignMessageRequest

class ETHSignResponse(google.protobuf.message.Message):
Expand Down
3 changes: 2 additions & 1 deletion py/send_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,8 @@ def _sign_eth_message(self) -> None:
msg_hex = binascii.hexlify(msg_bytes).decode("utf-8")
print(f"signing\nbytes: {repr(msg_bytes)}\nhex: 0x{msg_hex}")
sig = self._device.eth_sign_msg(
msg=msg_bytes, keypath=[44 + HARDENED, 60 + HARDENED, 0 + HARDENED, 0, 0]
msg=msg_bytes,
keypath=[44 + HARDENED, 60 + HARDENED, 0 + HARDENED, 0, 0],
)

print("Signature: 0x{}".format(binascii.hexlify(sig).decode("utf-8")))
Expand Down
8 changes: 4 additions & 4 deletions src/apps/eth/eth_params.c
Original file line number Diff line number Diff line change
Expand Up @@ -16207,17 +16207,17 @@ static const app_eth_erc20_params_t _ethereum_erc20_params[] = {
};

const app_eth_erc20_params_t* app_eth_erc20_params_get(
ETHCoin coin,
uint64_t chain_id,
const uint8_t* contract_address)
{
const app_eth_erc20_params_t* erc20_params;
size_t len;
switch (coin) {
case ETHCoin_ETH:
switch (chain_id) {
case 1:
erc20_params = _ethereum_erc20_params;
len = sizeof(_ethereum_erc20_params) / sizeof(app_eth_erc20_params_t);
break;
case ETHCoin_RopstenETH:
case 3:
erc20_params = _ropsten_erc20_params;
len = sizeof(_ropsten_erc20_params) / sizeof(app_eth_erc20_params_t);
break;
Expand Down
Loading

0 comments on commit 234cf09

Please sign in to comment.