diff --git a/CMakeLists.txt b/CMakeLists.txt index f96ef5d50e..1f81fd45e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,8 +88,8 @@ endif() # # Versions MUST contain three parts and start with lowercase 'v'. # Example 'v1.0.0'. They MUST not contain a pre-release label such as '-beta'. -set(FIRMWARE_VERSION "v9.16.0") -set(FIRMWARE_BTC_ONLY_VERSION "v9.16.0") +set(FIRMWARE_VERSION "v9.17.0") +set(FIRMWARE_BTC_ONLY_VERSION "v9.17.0") set(BOOTLOADER_VERSION "v1.0.5") find_package(PythonInterp 3.6 REQUIRED) diff --git a/messages/keystore.proto b/messages/keystore.proto index e4a94e6d50..4227a6c045 100644 --- a/messages/keystore.proto +++ b/messages/keystore.proto @@ -4,6 +4,8 @@ syntax = "proto3"; package shiftcrypto.bitbox02; +import "google/protobuf/empty.proto"; + message ElectrumEncryptionKeyRequest { repeated uint32 keypath = 1; } @@ -13,7 +15,13 @@ message ElectrumEncryptionKeyResponse { } message BIP85Request { + oneof app { + google.protobuf.Empty bip39 = 1; + } } message BIP85Response { + oneof app { + google.protobuf.Empty bip39 = 1; + } } diff --git a/py/bitbox02/bitbox02/bitbox02/bitbox02.py b/py/bitbox02/bitbox02/bitbox02/bitbox02.py index 19a59f6662..d9c19e14b5 100644 --- a/py/bitbox02/bitbox02/bitbox02/bitbox02.py +++ b/py/bitbox02/bitbox02/bitbox02/bitbox02.py @@ -43,6 +43,7 @@ from bitbox02.communication.generated import common_pb2 as common from bitbox02.communication.generated import keystore_pb2 as keystore from bitbox02.communication.generated import antiklepto_pb2 as antiklepto + import google.protobuf.empty_pb2 # pylint: disable=unused-import # We export it in __init__.py @@ -678,13 +679,17 @@ def electrum_encryption_key(self, keypath: Sequence[int]) -> str: ) return self._msg_query(request).electrum_encryption_key.key - def bip85(self) -> None: - """Invokes the BIP-85 workflow on the device""" - self._require_atleast(semver.VersionInfo(9, 16, 0)) + def bip85_39(self) -> None: + """Invokes the BIP85-BIP39 workflow on the device""" + self._require_atleast(semver.VersionInfo(9, 17, 0)) # pylint: disable=no-member request = hww.Request() - request.bip85.CopyFrom(keystore.BIP85Request()) + request.bip85.CopyFrom( + keystore.BIP85Request( + bip39=google.protobuf.empty_pb2.Empty(), + ) + ) self._msg_query(request) def enable_mnemonic_passphrase(self) -> None: diff --git a/py/bitbox02/bitbox02/communication/generated/keystore_pb2.py b/py/bitbox02/bitbox02/communication/generated/keystore_pb2.py index 66139dc44e..78178e5d24 100644 --- a/py/bitbox02/bitbox02/communication/generated/keystore_pb2.py +++ b/py/bitbox02/bitbox02/communication/generated/keystore_pb2.py @@ -11,21 +11,22 @@ _sym_db = _symbol_database.Default() +from google.protobuf import empty_pb2 as google_dot_protobuf_dot_empty__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0ekeystore.proto\x12\x14shiftcrypto.bitbox02\"/\n\x1c\x45lectrumEncryptionKeyRequest\x12\x0f\n\x07keypath\x18\x01 \x03(\r\",\n\x1d\x45lectrumEncryptionKeyResponse\x12\x0b\n\x03key\x18\x01 \x01(\t\"\x0e\n\x0c\x42IP85Request\"\x0f\n\rBIP85Responseb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0ekeystore.proto\x12\x14shiftcrypto.bitbox02\x1a\x1bgoogle/protobuf/empty.proto\"/\n\x1c\x45lectrumEncryptionKeyRequest\x12\x0f\n\x07keypath\x18\x01 \x03(\r\",\n\x1d\x45lectrumEncryptionKeyResponse\x12\x0b\n\x03key\x18\x01 \x01(\t\">\n\x0c\x42IP85Request\x12\'\n\x05\x62ip39\x18\x01 \x01(\x0b\x32\x16.google.protobuf.EmptyH\x00\x42\x05\n\x03\x61pp\"?\n\rBIP85Response\x12\'\n\x05\x62ip39\x18\x01 \x01(\x0b\x32\x16.google.protobuf.EmptyH\x00\x42\x05\n\x03\x61ppb\x06proto3') _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'keystore_pb2', globals()) if _descriptor._USE_C_DESCRIPTORS == False: DESCRIPTOR._options = None - _ELECTRUMENCRYPTIONKEYREQUEST._serialized_start=40 - _ELECTRUMENCRYPTIONKEYREQUEST._serialized_end=87 - _ELECTRUMENCRYPTIONKEYRESPONSE._serialized_start=89 - _ELECTRUMENCRYPTIONKEYRESPONSE._serialized_end=133 - _BIP85REQUEST._serialized_start=135 - _BIP85REQUEST._serialized_end=149 - _BIP85RESPONSE._serialized_start=151 - _BIP85RESPONSE._serialized_end=166 + _ELECTRUMENCRYPTIONKEYREQUEST._serialized_start=69 + _ELECTRUMENCRYPTIONKEYREQUEST._serialized_end=116 + _ELECTRUMENCRYPTIONKEYRESPONSE._serialized_start=118 + _ELECTRUMENCRYPTIONKEYRESPONSE._serialized_end=162 + _BIP85REQUEST._serialized_start=164 + _BIP85REQUEST._serialized_end=226 + _BIP85RESPONSE._serialized_start=228 + _BIP85RESPONSE._serialized_end=291 # @@protoc_insertion_point(module_scope) diff --git a/py/bitbox02/bitbox02/communication/generated/keystore_pb2.pyi b/py/bitbox02/bitbox02/communication/generated/keystore_pb2.pyi index 03ef6c3450..8bddce4595 100644 --- a/py/bitbox02/bitbox02/communication/generated/keystore_pb2.pyi +++ b/py/bitbox02/bitbox02/communication/generated/keystore_pb2.pyi @@ -4,6 +4,7 @@ isort:skip_file """ import builtins import google.protobuf.descriptor +import google.protobuf.empty_pb2 import google.protobuf.internal.containers import google.protobuf.message import typing @@ -36,12 +37,28 @@ global___ElectrumEncryptionKeyResponse = ElectrumEncryptionKeyResponse class BIP85Request(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor + BIP39_FIELD_NUMBER: builtins.int + @property + def bip39(self) -> google.protobuf.empty_pb2.Empty: ... def __init__(self, + *, + bip39: typing.Optional[google.protobuf.empty_pb2.Empty] = ..., ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["app",b"app","bip39",b"bip39"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["app",b"app","bip39",b"bip39"]) -> None: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["app",b"app"]) -> typing.Optional[typing_extensions.Literal["bip39"]]: ... global___BIP85Request = BIP85Request class BIP85Response(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor + BIP39_FIELD_NUMBER: builtins.int + @property + def bip39(self) -> google.protobuf.empty_pb2.Empty: ... def __init__(self, + *, + bip39: typing.Optional[google.protobuf.empty_pb2.Empty] = ..., ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["app",b"app","bip39",b"bip39"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["app",b"app","bip39",b"bip39"]) -> None: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["app",b"app"]) -> typing.Optional[typing_extensions.Literal["bip39"]]: ... global___BIP85Response = BIP85Response diff --git a/py/send_message.py b/py/send_message.py index 47fa429ce9..330d2ac860 100755 --- a/py/send_message.py +++ b/py/send_message.py @@ -340,8 +340,8 @@ def _get_electrum_encryption_key(self) -> None: ), ) - def _bip85(self) -> None: - self._device.bip85() + def _bip85_39(self) -> None: + self._device.bip85_39() def _btc_address(self) -> None: def address(display: bool) -> str: @@ -1391,7 +1391,7 @@ def _menu_init(self) -> None: ("Sign Ethereum Typed Message (EIP-712)", self._sign_eth_typed_message), ("Cardano", self._cardano), ("Show Electrum wallet encryption key", self._get_electrum_encryption_key), - ("BIP85", self._bip85), + ("BIP85 - BIP39", self._bip85_39), ("Reset Device", self._reset_device), ) choice = ask_user(choices) diff --git a/src/rust/bitbox02-rust/src/hww/api/bip85.rs b/src/rust/bitbox02-rust/src/hww/api/bip85.rs index 89b72a110b..9ae7f69d88 100644 --- a/src/rust/bitbox02-rust/src/hww/api/bip85.rs +++ b/src/rust/bitbox02-rust/src/hww/api/bip85.rs @@ -24,9 +24,19 @@ use crate::workflow::{confirm, menu, mnemonic, status, trinary_input_string}; use alloc::vec::Vec; +/// Processes a BIP-85 API call. +pub async fn process(request: &pb::Bip85Request) -> Result { + match request.app { + None => Err(Error::InvalidInput), + Some(pb::bip85_request::App::Bip39(())) => Ok(Response::Bip85(pb::Bip85Response { + app: Some(pb::bip85_response::App::Bip39(process_bip39().await?)), + })), + } +} + /// Derives and displays a BIP-39 seed according to BIP-85: /// https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#bip39. -pub async fn process(pb::Bip85Request {}: &pb::Bip85Request) -> Result { +async fn process_bip39() -> Result<(), Error> { confirm::confirm(&confirm::Params { title: "BIP-85", body: "Derive BIP-39\nmnemonic?", @@ -104,5 +114,5 @@ pub async fn process(pb::Bip85Request {}: &pb::Bip85Request) -> Result, +} +/// Nested message and enum types in `BIP85Request`. +pub mod bip85_request { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum App { + #[prost(message, tag = "1")] + Bip39(()), + } +} #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct Bip85Response {} +pub struct Bip85Response { + #[prost(oneof = "bip85_response::App", tags = "1")] + pub app: ::core::option::Option, +} +/// Nested message and enum types in `BIP85Response`. +pub mod bip85_response { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum App { + #[prost(message, tag = "1")] + Bip39(()), + } +} #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ShowMnemonicRequest {}