diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d5d97c67..c6dbd97d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ customers cannot upgrade their bootloader, its changes are recorded separately. - Update manufacturer HID descriptor to bitbox.swiss - Ethereum: remove deprecated Goerli network - SD card: solve backup bug when sd card is re-inserted +- Cardano: allow serialization using 258-tagged sets ### 9.21.0 - Bitcoin: add support for sending to silent payment (BIP-352) addresses diff --git a/CMakeLists.txt b/CMakeLists.txt index 88662b040..17e5672a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,8 +91,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.21.0") -set(FIRMWARE_BTC_ONLY_VERSION "v9.21.0") +set(FIRMWARE_VERSION "v9.22.0") +set(FIRMWARE_BTC_ONLY_VERSION "v9.22.0") set(BOOTLOADER_VERSION "v1.0.7") find_package(PythonInterp 3.6 REQUIRED) diff --git a/messages/cardano.proto b/messages/cardano.proto index ead7ecb5c..54b661d43 100644 --- a/messages/cardano.proto +++ b/messages/cardano.proto @@ -126,6 +126,9 @@ message CardanoSignTransactionRequest { repeated Withdrawal withdrawals = 7; uint64 validity_interval_start = 8; bool allow_zero_ttl = 9; // include ttl even if it is zero + // Tag arrays in the transaction serialization with the 258 tag. + // See https://github.com/IntersectMBO/cardano-ledger/blob/6e2d37cc0f47bd02e89b4ce9f78b59c35c958e96/eras/conway/impl/cddl-files/extra.cddl#L5 + bool tag_cbor_sets = 10; } message CardanoSignTransactionResponse { diff --git a/py/bitbox02/bitbox02/bitbox02/bitbox02.py b/py/bitbox02/bitbox02/bitbox02/bitbox02.py index 36b831c57..768a657e7 100644 --- a/py/bitbox02/bitbox02/bitbox02/bitbox02.py +++ b/py/bitbox02/bitbox02/bitbox02/bitbox02.py @@ -1174,6 +1174,8 @@ def cardano_address(self, address: cardano.CardanoAddressRequest) -> str: def cardano_sign_transaction( self, transaction: cardano.CardanoSignTransactionRequest ) -> cardano.CardanoSignTransactionResponse: + if transaction.tag_cbor_sets: + self._require_atleast(semver.VersionInfo(9, 22, 0)) request = cardano.CardanoRequest(sign_transaction=transaction) return self._cardano_msg_query( request, expected_response="sign_transaction" diff --git a/py/bitbox02/bitbox02/communication/generated/cardano_pb2.py b/py/bitbox02/bitbox02/communication/generated/cardano_pb2.py index ff26c411c..7996c1187 100644 --- a/py/bitbox02/bitbox02/communication/generated/cardano_pb2.py +++ b/py/bitbox02/bitbox02/communication/generated/cardano_pb2.py @@ -14,15 +14,15 @@ from . import common_pb2 as common__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rcardano.proto\x12\x14shiftcrypto.bitbox02\x1a\x0c\x63ommon.proto\"F\n\x13\x43\x61rdanoXpubsRequest\x12/\n\x08keypaths\x18\x01 \x03(\x0b\x32\x1d.shiftcrypto.bitbox02.Keypath\"%\n\x14\x43\x61rdanoXpubsResponse\x12\r\n\x05xpubs\x18\x01 \x03(\x0c\"\x9e\x01\n\x13\x43\x61rdanoScriptConfig\x12\x43\n\x07pkh_skh\x18\x01 \x01(\x0b\x32\x30.shiftcrypto.bitbox02.CardanoScriptConfig.PkhSkhH\x00\x1a\x38\n\x06PkhSkh\x12\x17\n\x0fkeypath_payment\x18\x01 \x03(\r\x12\x15\n\rkeypath_stake\x18\x02 \x03(\rB\x08\n\x06\x63onfig\"\xa1\x01\n\x15\x43\x61rdanoAddressRequest\x12\x35\n\x07network\x18\x01 \x01(\x0e\x32$.shiftcrypto.bitbox02.CardanoNetwork\x12\x0f\n\x07\x64isplay\x18\x02 \x01(\x08\x12@\n\rscript_config\x18\x03 \x01(\x0b\x32).shiftcrypto.bitbox02.CardanoScriptConfig\"\x99\r\n\x1d\x43\x61rdanoSignTransactionRequest\x12\x35\n\x07network\x18\x01 \x01(\x0e\x32$.shiftcrypto.bitbox02.CardanoNetwork\x12I\n\x06inputs\x18\x02 \x03(\x0b\x32\x39.shiftcrypto.bitbox02.CardanoSignTransactionRequest.Input\x12K\n\x07outputs\x18\x03 \x03(\x0b\x32:.shiftcrypto.bitbox02.CardanoSignTransactionRequest.Output\x12\x0b\n\x03\x66\x65\x65\x18\x04 \x01(\x04\x12\x0b\n\x03ttl\x18\x05 \x01(\x04\x12U\n\x0c\x63\x65rtificates\x18\x06 \x03(\x0b\x32?.shiftcrypto.bitbox02.CardanoSignTransactionRequest.Certificate\x12S\n\x0bwithdrawals\x18\x07 \x03(\x0b\x32>.shiftcrypto.bitbox02.CardanoSignTransactionRequest.Withdrawal\x12\x1f\n\x17validity_interval_start\x18\x08 \x01(\x04\x12\x16\n\x0e\x61llow_zero_ttl\x18\t \x01(\x08\x1aG\n\x05Input\x12\x0f\n\x07keypath\x18\x01 \x03(\r\x12\x15\n\rprev_out_hash\x18\x02 \x01(\x0c\x12\x16\n\x0eprev_out_index\x18\x03 \x01(\r\x1a\xa1\x01\n\nAssetGroup\x12\x11\n\tpolicy_id\x18\x01 \x01(\x0c\x12T\n\x06tokens\x18\x02 \x03(\x0b\x32\x44.shiftcrypto.bitbox02.CardanoSignTransactionRequest.AssetGroup.Token\x1a*\n\x05Token\x12\x12\n\nasset_name\x18\x01 \x01(\x0c\x12\r\n\x05value\x18\x02 \x01(\x04\x1a\xc8\x01\n\x06Output\x12\x17\n\x0f\x65ncoded_address\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x04\x12@\n\rscript_config\x18\x03 \x01(\x0b\x32).shiftcrypto.bitbox02.CardanoScriptConfig\x12T\n\x0c\x61sset_groups\x18\x04 \x03(\x0b\x32>.shiftcrypto.bitbox02.CardanoSignTransactionRequest.AssetGroup\x1a\xc3\x05\n\x0b\x43\x65rtificate\x12;\n\x12stake_registration\x18\x01 \x01(\x0b\x32\x1d.shiftcrypto.bitbox02.KeypathH\x00\x12=\n\x14stake_deregistration\x18\x02 \x01(\x0b\x32\x1d.shiftcrypto.bitbox02.KeypathH\x00\x12k\n\x10stake_delegation\x18\x03 \x01(\x0b\x32O.shiftcrypto.bitbox02.CardanoSignTransactionRequest.Certificate.StakeDelegationH\x00\x12i\n\x0fvote_delegation\x18\n \x01(\x0b\x32N.shiftcrypto.bitbox02.CardanoSignTransactionRequest.Certificate.VoteDelegationH\x00\x1a\x38\n\x0fStakeDelegation\x12\x0f\n\x07keypath\x18\x01 \x03(\r\x12\x14\n\x0cpool_keyhash\x18\x02 \x01(\x0c\x1a\x9d\x02\n\x0eVoteDelegation\x12\x0f\n\x07keypath\x18\x01 \x03(\r\x12l\n\x04type\x18\x02 \x01(\x0e\x32^.shiftcrypto.bitbox02.CardanoSignTransactionRequest.Certificate.VoteDelegation.CardanoDRepType\x12\x1a\n\rdrep_credhash\x18\x03 \x01(\x0cH\x00\x88\x01\x01\"^\n\x0f\x43\x61rdanoDRepType\x12\x0c\n\x08KEY_HASH\x10\x00\x12\x0f\n\x0bSCRIPT_HASH\x10\x01\x12\x12\n\x0e\x41LWAYS_ABSTAIN\x10\x02\x12\x18\n\x14\x41LWAYS_NO_CONFIDENCE\x10\x03\x42\x10\n\x0e_drep_credhashB\x06\n\x04\x63\x65rt\x1a,\n\nWithdrawal\x12\x0f\n\x07keypath\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x04\"\xb9\x01\n\x1e\x43\x61rdanoSignTransactionResponse\x12^\n\x11shelley_witnesses\x18\x01 \x03(\x0b\x32\x43.shiftcrypto.bitbox02.CardanoSignTransactionResponse.ShelleyWitness\x1a\x37\n\x0eShelleyWitness\x12\x12\n\npublic_key\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\"\xe8\x01\n\x0e\x43\x61rdanoRequest\x12:\n\x05xpubs\x18\x01 \x01(\x0b\x32).shiftcrypto.bitbox02.CardanoXpubsRequestH\x00\x12>\n\x07\x61\x64\x64ress\x18\x02 \x01(\x0b\x32+.shiftcrypto.bitbox02.CardanoAddressRequestH\x00\x12O\n\x10sign_transaction\x18\x03 \x01(\x0b\x32\x33.shiftcrypto.bitbox02.CardanoSignTransactionRequestH\x00\x42\t\n\x07request\"\xde\x01\n\x0f\x43\x61rdanoResponse\x12;\n\x05xpubs\x18\x01 \x01(\x0b\x32*.shiftcrypto.bitbox02.CardanoXpubsResponseH\x00\x12\x30\n\x03pub\x18\x02 \x01(\x0b\x32!.shiftcrypto.bitbox02.PubResponseH\x00\x12P\n\x10sign_transaction\x18\x03 \x01(\x0b\x32\x34.shiftcrypto.bitbox02.CardanoSignTransactionResponseH\x00\x42\n\n\x08response*8\n\x0e\x43\x61rdanoNetwork\x12\x12\n\x0e\x43\x61rdanoMainnet\x10\x00\x12\x12\n\x0e\x43\x61rdanoTestnet\x10\x01\x62\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rcardano.proto\x12\x14shiftcrypto.bitbox02\x1a\x0c\x63ommon.proto\"F\n\x13\x43\x61rdanoXpubsRequest\x12/\n\x08keypaths\x18\x01 \x03(\x0b\x32\x1d.shiftcrypto.bitbox02.Keypath\"%\n\x14\x43\x61rdanoXpubsResponse\x12\r\n\x05xpubs\x18\x01 \x03(\x0c\"\x9e\x01\n\x13\x43\x61rdanoScriptConfig\x12\x43\n\x07pkh_skh\x18\x01 \x01(\x0b\x32\x30.shiftcrypto.bitbox02.CardanoScriptConfig.PkhSkhH\x00\x1a\x38\n\x06PkhSkh\x12\x17\n\x0fkeypath_payment\x18\x01 \x03(\r\x12\x15\n\rkeypath_stake\x18\x02 \x03(\rB\x08\n\x06\x63onfig\"\xa1\x01\n\x15\x43\x61rdanoAddressRequest\x12\x35\n\x07network\x18\x01 \x01(\x0e\x32$.shiftcrypto.bitbox02.CardanoNetwork\x12\x0f\n\x07\x64isplay\x18\x02 \x01(\x08\x12@\n\rscript_config\x18\x03 \x01(\x0b\x32).shiftcrypto.bitbox02.CardanoScriptConfig\"\xb0\r\n\x1d\x43\x61rdanoSignTransactionRequest\x12\x35\n\x07network\x18\x01 \x01(\x0e\x32$.shiftcrypto.bitbox02.CardanoNetwork\x12I\n\x06inputs\x18\x02 \x03(\x0b\x32\x39.shiftcrypto.bitbox02.CardanoSignTransactionRequest.Input\x12K\n\x07outputs\x18\x03 \x03(\x0b\x32:.shiftcrypto.bitbox02.CardanoSignTransactionRequest.Output\x12\x0b\n\x03\x66\x65\x65\x18\x04 \x01(\x04\x12\x0b\n\x03ttl\x18\x05 \x01(\x04\x12U\n\x0c\x63\x65rtificates\x18\x06 \x03(\x0b\x32?.shiftcrypto.bitbox02.CardanoSignTransactionRequest.Certificate\x12S\n\x0bwithdrawals\x18\x07 \x03(\x0b\x32>.shiftcrypto.bitbox02.CardanoSignTransactionRequest.Withdrawal\x12\x1f\n\x17validity_interval_start\x18\x08 \x01(\x04\x12\x16\n\x0e\x61llow_zero_ttl\x18\t \x01(\x08\x12\x15\n\rtag_cbor_sets\x18\n \x01(\x08\x1aG\n\x05Input\x12\x0f\n\x07keypath\x18\x01 \x03(\r\x12\x15\n\rprev_out_hash\x18\x02 \x01(\x0c\x12\x16\n\x0eprev_out_index\x18\x03 \x01(\r\x1a\xa1\x01\n\nAssetGroup\x12\x11\n\tpolicy_id\x18\x01 \x01(\x0c\x12T\n\x06tokens\x18\x02 \x03(\x0b\x32\x44.shiftcrypto.bitbox02.CardanoSignTransactionRequest.AssetGroup.Token\x1a*\n\x05Token\x12\x12\n\nasset_name\x18\x01 \x01(\x0c\x12\r\n\x05value\x18\x02 \x01(\x04\x1a\xc8\x01\n\x06Output\x12\x17\n\x0f\x65ncoded_address\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x04\x12@\n\rscript_config\x18\x03 \x01(\x0b\x32).shiftcrypto.bitbox02.CardanoScriptConfig\x12T\n\x0c\x61sset_groups\x18\x04 \x03(\x0b\x32>.shiftcrypto.bitbox02.CardanoSignTransactionRequest.AssetGroup\x1a\xc3\x05\n\x0b\x43\x65rtificate\x12;\n\x12stake_registration\x18\x01 \x01(\x0b\x32\x1d.shiftcrypto.bitbox02.KeypathH\x00\x12=\n\x14stake_deregistration\x18\x02 \x01(\x0b\x32\x1d.shiftcrypto.bitbox02.KeypathH\x00\x12k\n\x10stake_delegation\x18\x03 \x01(\x0b\x32O.shiftcrypto.bitbox02.CardanoSignTransactionRequest.Certificate.StakeDelegationH\x00\x12i\n\x0fvote_delegation\x18\n \x01(\x0b\x32N.shiftcrypto.bitbox02.CardanoSignTransactionRequest.Certificate.VoteDelegationH\x00\x1a\x38\n\x0fStakeDelegation\x12\x0f\n\x07keypath\x18\x01 \x03(\r\x12\x14\n\x0cpool_keyhash\x18\x02 \x01(\x0c\x1a\x9d\x02\n\x0eVoteDelegation\x12\x0f\n\x07keypath\x18\x01 \x03(\r\x12l\n\x04type\x18\x02 \x01(\x0e\x32^.shiftcrypto.bitbox02.CardanoSignTransactionRequest.Certificate.VoteDelegation.CardanoDRepType\x12\x1a\n\rdrep_credhash\x18\x03 \x01(\x0cH\x00\x88\x01\x01\"^\n\x0f\x43\x61rdanoDRepType\x12\x0c\n\x08KEY_HASH\x10\x00\x12\x0f\n\x0bSCRIPT_HASH\x10\x01\x12\x12\n\x0e\x41LWAYS_ABSTAIN\x10\x02\x12\x18\n\x14\x41LWAYS_NO_CONFIDENCE\x10\x03\x42\x10\n\x0e_drep_credhashB\x06\n\x04\x63\x65rt\x1a,\n\nWithdrawal\x12\x0f\n\x07keypath\x18\x01 \x03(\r\x12\r\n\x05value\x18\x02 \x01(\x04\"\xb9\x01\n\x1e\x43\x61rdanoSignTransactionResponse\x12^\n\x11shelley_witnesses\x18\x01 \x03(\x0b\x32\x43.shiftcrypto.bitbox02.CardanoSignTransactionResponse.ShelleyWitness\x1a\x37\n\x0eShelleyWitness\x12\x12\n\npublic_key\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\"\xe8\x01\n\x0e\x43\x61rdanoRequest\x12:\n\x05xpubs\x18\x01 \x01(\x0b\x32).shiftcrypto.bitbox02.CardanoXpubsRequestH\x00\x12>\n\x07\x61\x64\x64ress\x18\x02 \x01(\x0b\x32+.shiftcrypto.bitbox02.CardanoAddressRequestH\x00\x12O\n\x10sign_transaction\x18\x03 \x01(\x0b\x32\x33.shiftcrypto.bitbox02.CardanoSignTransactionRequestH\x00\x42\t\n\x07request\"\xde\x01\n\x0f\x43\x61rdanoResponse\x12;\n\x05xpubs\x18\x01 \x01(\x0b\x32*.shiftcrypto.bitbox02.CardanoXpubsResponseH\x00\x12\x30\n\x03pub\x18\x02 \x01(\x0b\x32!.shiftcrypto.bitbox02.PubResponseH\x00\x12P\n\x10sign_transaction\x18\x03 \x01(\x0b\x32\x34.shiftcrypto.bitbox02.CardanoSignTransactionResponseH\x00\x42\n\n\x08response*8\n\x0e\x43\x61rdanoNetwork\x12\x12\n\x0e\x43\x61rdanoMainnet\x10\x00\x12\x12\n\x0e\x43\x61rdanoTestnet\x10\x01\x62\x06proto3') _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'cardano_pb2', globals()) if _descriptor._USE_C_DESCRIPTORS == False: DESCRIPTOR._options = None - _CARDANONETWORK._serialized_start=2829 - _CARDANONETWORK._serialized_end=2885 + _CARDANONETWORK._serialized_start=2852 + _CARDANONETWORK._serialized_end=2908 _CARDANOXPUBSREQUEST._serialized_start=53 _CARDANOXPUBSREQUEST._serialized_end=123 _CARDANOXPUBSRESPONSE._serialized_start=125 @@ -34,31 +34,31 @@ _CARDANOADDRESSREQUEST._serialized_start=326 _CARDANOADDRESSREQUEST._serialized_end=487 _CARDANOSIGNTRANSACTIONREQUEST._serialized_start=490 - _CARDANOSIGNTRANSACTIONREQUEST._serialized_end=2179 - _CARDANOSIGNTRANSACTIONREQUEST_INPUT._serialized_start=985 - _CARDANOSIGNTRANSACTIONREQUEST_INPUT._serialized_end=1056 - _CARDANOSIGNTRANSACTIONREQUEST_ASSETGROUP._serialized_start=1059 - _CARDANOSIGNTRANSACTIONREQUEST_ASSETGROUP._serialized_end=1220 - _CARDANOSIGNTRANSACTIONREQUEST_ASSETGROUP_TOKEN._serialized_start=1178 - _CARDANOSIGNTRANSACTIONREQUEST_ASSETGROUP_TOKEN._serialized_end=1220 - _CARDANOSIGNTRANSACTIONREQUEST_OUTPUT._serialized_start=1223 - _CARDANOSIGNTRANSACTIONREQUEST_OUTPUT._serialized_end=1423 - _CARDANOSIGNTRANSACTIONREQUEST_CERTIFICATE._serialized_start=1426 - _CARDANOSIGNTRANSACTIONREQUEST_CERTIFICATE._serialized_end=2133 - _CARDANOSIGNTRANSACTIONREQUEST_CERTIFICATE_STAKEDELEGATION._serialized_start=1781 - _CARDANOSIGNTRANSACTIONREQUEST_CERTIFICATE_STAKEDELEGATION._serialized_end=1837 - _CARDANOSIGNTRANSACTIONREQUEST_CERTIFICATE_VOTEDELEGATION._serialized_start=1840 - _CARDANOSIGNTRANSACTIONREQUEST_CERTIFICATE_VOTEDELEGATION._serialized_end=2125 - _CARDANOSIGNTRANSACTIONREQUEST_CERTIFICATE_VOTEDELEGATION_CARDANODREPTYPE._serialized_start=2013 - _CARDANOSIGNTRANSACTIONREQUEST_CERTIFICATE_VOTEDELEGATION_CARDANODREPTYPE._serialized_end=2107 - _CARDANOSIGNTRANSACTIONREQUEST_WITHDRAWAL._serialized_start=2135 - _CARDANOSIGNTRANSACTIONREQUEST_WITHDRAWAL._serialized_end=2179 - _CARDANOSIGNTRANSACTIONRESPONSE._serialized_start=2182 - _CARDANOSIGNTRANSACTIONRESPONSE._serialized_end=2367 - _CARDANOSIGNTRANSACTIONRESPONSE_SHELLEYWITNESS._serialized_start=2312 - _CARDANOSIGNTRANSACTIONRESPONSE_SHELLEYWITNESS._serialized_end=2367 - _CARDANOREQUEST._serialized_start=2370 - _CARDANOREQUEST._serialized_end=2602 - _CARDANORESPONSE._serialized_start=2605 - _CARDANORESPONSE._serialized_end=2827 + _CARDANOSIGNTRANSACTIONREQUEST._serialized_end=2202 + _CARDANOSIGNTRANSACTIONREQUEST_INPUT._serialized_start=1008 + _CARDANOSIGNTRANSACTIONREQUEST_INPUT._serialized_end=1079 + _CARDANOSIGNTRANSACTIONREQUEST_ASSETGROUP._serialized_start=1082 + _CARDANOSIGNTRANSACTIONREQUEST_ASSETGROUP._serialized_end=1243 + _CARDANOSIGNTRANSACTIONREQUEST_ASSETGROUP_TOKEN._serialized_start=1201 + _CARDANOSIGNTRANSACTIONREQUEST_ASSETGROUP_TOKEN._serialized_end=1243 + _CARDANOSIGNTRANSACTIONREQUEST_OUTPUT._serialized_start=1246 + _CARDANOSIGNTRANSACTIONREQUEST_OUTPUT._serialized_end=1446 + _CARDANOSIGNTRANSACTIONREQUEST_CERTIFICATE._serialized_start=1449 + _CARDANOSIGNTRANSACTIONREQUEST_CERTIFICATE._serialized_end=2156 + _CARDANOSIGNTRANSACTIONREQUEST_CERTIFICATE_STAKEDELEGATION._serialized_start=1804 + _CARDANOSIGNTRANSACTIONREQUEST_CERTIFICATE_STAKEDELEGATION._serialized_end=1860 + _CARDANOSIGNTRANSACTIONREQUEST_CERTIFICATE_VOTEDELEGATION._serialized_start=1863 + _CARDANOSIGNTRANSACTIONREQUEST_CERTIFICATE_VOTEDELEGATION._serialized_end=2148 + _CARDANOSIGNTRANSACTIONREQUEST_CERTIFICATE_VOTEDELEGATION_CARDANODREPTYPE._serialized_start=2036 + _CARDANOSIGNTRANSACTIONREQUEST_CERTIFICATE_VOTEDELEGATION_CARDANODREPTYPE._serialized_end=2130 + _CARDANOSIGNTRANSACTIONREQUEST_WITHDRAWAL._serialized_start=2158 + _CARDANOSIGNTRANSACTIONREQUEST_WITHDRAWAL._serialized_end=2202 + _CARDANOSIGNTRANSACTIONRESPONSE._serialized_start=2205 + _CARDANOSIGNTRANSACTIONRESPONSE._serialized_end=2390 + _CARDANOSIGNTRANSACTIONRESPONSE_SHELLEYWITNESS._serialized_start=2335 + _CARDANOSIGNTRANSACTIONRESPONSE_SHELLEYWITNESS._serialized_end=2390 + _CARDANOREQUEST._serialized_start=2393 + _CARDANOREQUEST._serialized_end=2625 + _CARDANORESPONSE._serialized_start=2628 + _CARDANORESPONSE._serialized_end=2850 # @@protoc_insertion_point(module_scope) diff --git a/py/bitbox02/bitbox02/communication/generated/cardano_pb2.pyi b/py/bitbox02/bitbox02/communication/generated/cardano_pb2.pyi index 0e531bcf8..a500b863a 100644 --- a/py/bitbox02/bitbox02/communication/generated/cardano_pb2.pyi +++ b/py/bitbox02/bitbox02/communication/generated/cardano_pb2.pyi @@ -282,6 +282,7 @@ class CardanoSignTransactionRequest(google.protobuf.message.Message): WITHDRAWALS_FIELD_NUMBER: builtins.int VALIDITY_INTERVAL_START_FIELD_NUMBER: builtins.int ALLOW_ZERO_TTL_FIELD_NUMBER: builtins.int + TAG_CBOR_SETS_FIELD_NUMBER: builtins.int network: global___CardanoNetwork.ValueType @property def inputs(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___CardanoSignTransactionRequest.Input]: ... @@ -297,6 +298,7 @@ class CardanoSignTransactionRequest(google.protobuf.message.Message): allow_zero_ttl: builtins.bool """include ttl even if it is zero""" + tag_cbor_sets: builtins.bool def __init__(self, *, network: global___CardanoNetwork.ValueType = ..., @@ -308,8 +310,9 @@ class CardanoSignTransactionRequest(google.protobuf.message.Message): withdrawals: typing.Optional[typing.Iterable[global___CardanoSignTransactionRequest.Withdrawal]] = ..., validity_interval_start: builtins.int = ..., allow_zero_ttl: builtins.bool = ..., + tag_cbor_sets: builtins.bool = ..., ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal["allow_zero_ttl",b"allow_zero_ttl","certificates",b"certificates","fee",b"fee","inputs",b"inputs","network",b"network","outputs",b"outputs","ttl",b"ttl","validity_interval_start",b"validity_interval_start","withdrawals",b"withdrawals"]) -> None: ... + def ClearField(self, field_name: typing_extensions.Literal["allow_zero_ttl",b"allow_zero_ttl","certificates",b"certificates","fee",b"fee","inputs",b"inputs","network",b"network","outputs",b"outputs","tag_cbor_sets",b"tag_cbor_sets","ttl",b"ttl","validity_interval_start",b"validity_interval_start","withdrawals",b"withdrawals"]) -> None: ... global___CardanoSignTransactionRequest = CardanoSignTransactionRequest class CardanoSignTransactionResponse(google.protobuf.message.Message): diff --git a/src/rust/bitbox02-rust/src/hww/api/cardano/sign_transaction.rs b/src/rust/bitbox02-rust/src/hww/api/cardano/sign_transaction.rs index a7e88c360..306e495c7 100644 --- a/src/rust/bitbox02-rust/src/hww/api/cardano/sign_transaction.rs +++ b/src/rust/bitbox02-rust/src/hww/api/cardano/sign_transaction.rs @@ -400,10 +400,7 @@ mod tests { ], fee: 170499, ttl: 41115811, - allow_zero_ttl: false, - certificates: vec![], - withdrawals: vec![], - validity_interval_start: 0, + ..Default::default() }; static mut TOTAL_CONFIRMED: bool = false; @@ -511,7 +508,6 @@ mod tests { ], fee: 191681, ttl: 41539125, - allow_zero_ttl: false, certificates: vec![ Certificate{ cert: Some(Cert::StakeRegistration( @@ -529,8 +525,7 @@ mod tests { )), }, ], - withdrawals: vec![], - validity_interval_start: 0, + ..Default::default() }; static mut CONFIRM_COUNTER: u32 = 0; @@ -632,7 +627,6 @@ mod tests { ], fee: 191681, ttl: 41539125, - allow_zero_ttl: false, certificates: vec![ Certificate{ cert: Some(Cert::StakeDeregistration( @@ -642,8 +636,7 @@ mod tests { )), }, ], - withdrawals: vec![], - validity_interval_start: 0, + ..Default::default() }; static mut CONFIRM_COUNTER: u32 = 0; @@ -728,7 +721,6 @@ mod tests { ], fee: 191681, ttl: 41539125, - allow_zero_ttl: false, certificates: vec![ Certificate{ cert: Some(Cert::VoteDelegation( @@ -740,8 +732,7 @@ mod tests { )), }, ], - withdrawals: vec![], - validity_interval_start: 0, + ..Default::default() }; static mut CONFIRM_COUNTER: u32 = 0; @@ -826,15 +817,13 @@ mod tests { ], fee: 175157, ttl: 41788708, - allow_zero_ttl: false, - certificates: vec![], withdrawals: vec![ pb::cardano_sign_transaction_request::Withdrawal { keypath: vec![1852 + HARDENED, 1815 + HARDENED, HARDENED, 2, 0], value: 1234567, }, ], - validity_interval_start: 0, + ..Default::default() }; static mut CONFIRM_COUNTER: u32 = 0; @@ -920,11 +909,7 @@ mod tests { }, ], fee: 170499, - ttl: 0, - allow_zero_ttl: false, - certificates: vec![], - withdrawals: vec![], - validity_interval_start: 0, + ..Default::default() }; mock(Data { @@ -981,9 +966,7 @@ mod tests { fee: 170499, ttl: 0, allow_zero_ttl: true, - certificates: vec![], - withdrawals: vec![], - validity_interval_start: 0, + ..Default::default() }; static mut CONFIRM_COUNTER: u32 = 0; @@ -1055,11 +1038,8 @@ mod tests { }, ], fee: 170499, - ttl: 0, - allow_zero_ttl: false, - certificates: vec![], - withdrawals: vec![], validity_interval_start: 41115811, + ..Default::default() }; static mut CONFIRM_COUNTER: u32 = 0; @@ -1121,10 +1101,9 @@ mod tests { ], fee: 170499, ttl: 41115810, - allow_zero_ttl: false, - certificates: vec![], - withdrawals: vec![], validity_interval_start: 41115811, // start > ttl, invalid + ..Default::default() + }; static mut CONFIRM_COUNTER: u32 = 0; @@ -1218,11 +1197,8 @@ mod tests { }, ], fee: 170499, - ttl: 0, - allow_zero_ttl: false, - certificates: vec![], - withdrawals: vec![], - validity_interval_start: 0, + ..Default::default() + }; static mut CONFIRM_COUNTER: u32 = 0; @@ -1325,12 +1301,8 @@ mod tests { }, ], fee: 170499, - ttl: 0, - allow_zero_ttl: false, - certificates: vec![], - withdrawals: vec![], - validity_interval_start: 0, - }; + ..Default::default() + }; static mut CONFIRM_COUNTER: u32 = 0; mock(Data { @@ -1364,6 +1336,59 @@ mod tests { assert_eq!(unsafe { CONFIRM_COUNTER }, 1); } + #[test] + fn test_sign_tx_tag_cbor_sets() { + let tx = pb::CardanoSignTransactionRequest { + network: CardanoNetwork::CardanoMainnet as _, + inputs: vec![pb::cardano_sign_transaction_request::Input { + keypath: vec![1852 + HARDENED, 1815 + HARDENED, HARDENED, 0, 0], + prev_out_hash: b"\x59\x86\x4e\xe7\x3c\xa5\xd9\x10\x98\xa3\x2b\x3c\xe9\x81\x1b\xac\x19\x96\xdc\xba\xef\xa6\xb6\x24\x7d\xca\xaf\xb5\x77\x9c\x25\x38".to_vec(), + prev_out_index: 0, + }], + outputs: vec![ + pb::cardano_sign_transaction_request::Output { + encoded_address: "addr1q9qfllpxg2vu4lq6rnpel4pvpp5xnv3kvvgtxk6k6wp4ff89xrhu8jnu3p33vnctc9eklee5dtykzyag5penc6dcmakqsqqgpt".into(), + value: 1000000, + script_config: None, + asset_groups: vec![], + }, + // change + pb::cardano_sign_transaction_request::Output { + encoded_address: "addr1q90tlskd4mh5kncmul7vx887j30tjtfgvap5n0g0rf9qqc7znmndrdhe7rwvqkw5c7mqnp4a3yflnvu6kff7l5dungvqmvu6hs".into(), + value: 4829501, + script_config: Some(CardanoScriptConfig{ + config: Some(pb::cardano_script_config::Config::PkhSkh(pb::cardano_script_config::PkhSkh { + keypath_payment: vec![1852 + HARDENED, 1815 + HARDENED, HARDENED, 0, 0], + keypath_stake: vec![1852 + HARDENED, 1815 + HARDENED, HARDENED, 2, 0], + })) + }), + asset_groups: vec![], + }, + ], + fee: 170499, + tag_cbor_sets: true, + ..Default::default() + }; + + mock(Data { + ui_confirm_create: Some(Box::new(|_params| true)), + ui_transaction_address_create: Some(Box::new(|_amount, _address| true)), + ui_transaction_fee_create: Some(Box::new(|_total, _fee, _longtouch| true)), + ..Default::default() + }); + mock_unlocked(); + let result = block_on(process(&tx)).unwrap(); + assert_eq!( + result, + Response::SignTransaction(pb::CardanoSignTransactionResponse { + shelley_witnesses: vec![ShelleyWitness { + public_key: b"\x1f\x17\xaf\xff\xe8\x05\x29\x7f\x8e\xc6\x54\x45\x82\xb7\xea\x91\xc3\x0d\xc1\xf9\x11\x9c\x5c\x2b\x26\x3e\x58\xfa\x36\x59\x31\x7d".to_vec(), + signature: b"\xa1\x53\x67\x4e\xa7\x65\xf3\x49\x27\x5d\x3f\xe4\x76\x01\x0a\x17\x5f\xbb\x73\xa1\x81\x21\x04\x71\x8f\xb8\xd0\x6d\xb4\x6a\xf7\x69\x46\x85\x56\x49\x36\x86\x54\xb8\x6b\x41\x9e\x65\x5c\xfe\x6f\xda\x67\xeb\x1f\x6a\xab\x40\xf1\xff\xdf\xcc\x6c\x3e\x93\x39\xa7\x07".to_vec(), + }] + }) + ); + } + #[test] fn test_validate_asset_groups() { assert!(validate_asset_groups(&[]).is_ok()); diff --git a/src/rust/bitbox02-rust/src/hww/api/cardano/sign_transaction/cbor.rs b/src/rust/bitbox02-rust/src/hww/api/cardano/sign_transaction/cbor.rs index 0e53e5dc9..c0a2bf899 100644 --- a/src/rust/bitbox02-rust/src/hww/api/cardano/sign_transaction/cbor.rs +++ b/src/rust/bitbox02-rust/src/hww/api/cardano/sign_transaction/cbor.rs @@ -69,6 +69,21 @@ pub fn encode_withdrawal_address( Ok(encoded) } +/// Start encoding a set: +/// https://github.com/IntersectMBO/cardano-ledger/blob/6e2d37cc0f47bd02e89b4ce9f78b59c35c958e96/eras/conway/impl/cddl-files/extra.cddl#L5 +/// tag258 indicates whether to use the tagged version or the untagged version. +fn encode_set_header( + encoder: &mut Encoder, + len: u64, + tag258: bool, +) -> Result<(), Error> { + if tag258 { + encoder.tag(minicbor::data::Tag::new(258))?; + } + encoder.array(len)?; + Ok(()) +} + /// CBOR encoding for Cardano transactions. /// /// The transaction must be verified/validated before calling this function. @@ -99,7 +114,8 @@ pub fn encode_transaction_body( encoder.map(num_map_entries)?; // Map entry 0 is an array of inputs. - encoder.u8(0)?.array(tx.inputs.len() as _)?; + encoder.u8(0)?; + encode_set_header(&mut encoder, tx.inputs.len() as _, tx.tag_cbor_sets)?; for input in tx.inputs.iter() { if input.prev_out_hash.len() != 32 { return Err(Error::InvalidInput); @@ -143,7 +159,8 @@ pub fn encode_transaction_body( } // Optional map entry 4 are the certificates: if !tx.certificates.is_empty() { - encoder.u8(4)?.array(tx.certificates.len() as _)?; + encoder.u8(4)?; + encode_set_header(&mut encoder, tx.certificates.len() as _, tx.tag_cbor_sets)?; for Certificate { cert } in tx.certificates.iter() { match cert.as_ref().ok_or(Error::InvalidInput)? { certificate::Cert::StakeRegistration(pb::Keypath { keypath }) => { diff --git a/src/rust/bitbox02-rust/src/shiftcrypto.bitbox02.rs b/src/rust/bitbox02-rust/src/shiftcrypto.bitbox02.rs index c14644e3f..b30b7eaf1 100644 --- a/src/rust/bitbox02-rust/src/shiftcrypto.bitbox02.rs +++ b/src/rust/bitbox02-rust/src/shiftcrypto.bitbox02.rs @@ -1019,6 +1019,8 @@ pub struct CardanoSignTransactionRequest { /// include ttl even if it is zero #[prost(bool, tag = "9")] pub allow_zero_ttl: bool, + #[prost(bool, tag = "10")] + pub tag_cbor_sets: bool, } /// Nested message and enum types in `CardanoSignTransactionRequest`. pub mod cardano_sign_transaction_request {