From e0fd0f81ced2e3d9b6445374d5f6a3f7c3b1aab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1n=20Maz=C3=A1k?= <42575685+janmazak@users.noreply.github.com> Date: Thu, 8 Dec 2022 10:22:55 +0100 Subject: [PATCH 001/105] Governance voting (CIP-0036) (#29) * refactor: hide 'reasonable' derivation path check details * refactor: hardnening of derivation path elements * refactor: rewrite bip44_isOrdinaryStakingKeyPath * refactor: remove unused functions * update Dockerfile * update protocol magic for testnets * feature: add export of governance voting keys * refactor: rename catalyst to governance voting * feature: CIP-36 governance voting registration * feature: allow third-party reward addresses * feature: sign governance vote * refactor: don't include BOLOS unnecessarily * update version and changelog * fix: governance voting key prefix gov_vk --- CHANGELOG.md | 19 +- Dockerfile | 8 +- Makefile | 4 +- doc/ins_sign_catalyst_registration.md | 87 -- ...ins_sign_governance_voting_registration.md | 145 +++ doc/ins_sign_tx.md | 18 +- fuzz/CMakeLists.txt | 2 +- src/addressUtilsByron_test.c | 2 +- src/auxDataHashBuilder.c | 195 ++- src/auxDataHashBuilder.h | 74 +- src/auxDataHashBuilder_test.c | 158 ++- src/bip44.c | 156 ++- src/bip44.h | 22 +- src/cardano.h | 9 +- src/common.h | 9 +- src/deriveNativeScriptHash.c | 2 +- src/getPublicKeys.c | 3 +- src/handlers.c | 2 + src/hash.h | 2 + src/messageSigning.c | 16 +- src/messageSigning.h | 8 +- src/securityPolicy.c | 175 ++- src/securityPolicy.h | 23 +- src/signGovernanceVote.c | 432 +++++++ src/signGovernanceVote.h | 45 + src/signTx.c | 66 +- src/signTx.h | 6 +- src/signTxAuxData.h | 2 +- src/signTxCatalystRegistration.c | 635 ---------- src/signTxCatalystRegistration.h | 51 - src/signTxGovernanceVotingRegistration.c | 1078 +++++++++++++++++ src/signTxGovernanceVotingRegistration.h | 70 ++ src/signTxOutput.c | 39 +- src/signTxUtils.c | 32 +- src/signTxUtils.h | 3 + src/state.h | 2 + src/txHashBuilder.c | 3 +- src/uiScreens.c | 2 +- src/utils.h | 3 +- src/votecastHashBuilder.c | 99 ++ src/votecastHashBuilder.h | 37 + 41 files changed, 2647 insertions(+), 1097 deletions(-) delete mode 100644 doc/ins_sign_catalyst_registration.md create mode 100644 doc/ins_sign_governance_voting_registration.md create mode 100644 src/signGovernanceVote.c create mode 100644 src/signGovernanceVote.h delete mode 100644 src/signTxCatalystRegistration.c delete mode 100644 src/signTxCatalystRegistration.h create mode 100644 src/signTxGovernanceVotingRegistration.c create mode 100644 src/signTxGovernanceVotingRegistration.h create mode 100644 src/votecastHashBuilder.c create mode 100644 src/votecastHashBuilder.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 88c8de3a..dd00d680 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,27 @@ # Change Log All notable changes to this project will be documented in this file. - + The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [5.0.0](TBD) - [TBD] +## [6.0.0](TBD) - [TBD] + +Support for governance voting (CIP-0036) + +### Added + +- export of governance voting keys (1694'/1815'/...) +- support for governance voting (signing of vote-cast fragments with 1694 keys) +- support for CIP-36 features (governance voting registration in transaction auxiliary data) + +### Changed + +- API for Catalyst voting registration (it is still possible to use CIP-0015 in auxiliary data) + + +## [5.0.0](https://github.com/LedgerHQ/app-cardano/compare/4.1.2...LedgerHQ:nanos_2.1.0_5.0.0) - [October 11th 2022] Support for Babbage era diff --git a/Dockerfile b/Dockerfile index 2216851e..ca21e882 100644 --- a/Dockerfile +++ b/Dockerfile @@ -59,17 +59,19 @@ RUN rustup target add thumbv6m-none-eabi # Python packages commonly used by apps RUN pip3 install ledgerblue pytest +ARG GIT_SERVER=https://github.com/LedgerHQ + # Latest Nano S SDK ENV NANOS_SDK=/opt/nanos-secure-sdk -RUN git clone --branch 2.1.0 --depth 1 https://github.com/LedgerHQ/nanos-secure-sdk.git "${NANOS_SDK}" +RUN git clone --branch 2.1.0 --depth 1 "$GIT_SERVER/nanos-secure-sdk.git" "$NANOS_SDK" # Latest Nano X SDK ENV NANOX_SDK=/opt/nanox-secure-sdk -RUN git clone --branch 2.0.2-2 --depth 1 https://github.com/LedgerHQ/nanox-secure-sdk.git "${NANOX_SDK}" +RUN git clone --branch 2.0.2-2 --depth 1 "$GIT_SERVER/nanox-secure-sdk.git" "$NANOX_SDK" # Latest Nano S+ SDK ENV NANOSP_SDK=/opt/nanosplus-secure-sdk -RUN git clone --branch 1.0.3 --depth 1 https://github.com/LedgerHQ/nanosplus-secure-sdk.git "${NANOSP_SDK}" +RUN git clone --branch 1.0.4 --depth 1 "$GIT_SERVER/nanosplus-secure-sdk.git" "$NANOSP_SDK" # Default SDK ENV BOLOS_SDK=${NANOS_SDK} diff --git a/Makefile b/Makefile index dc751102..ed327d43 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ #******************************************************************************* APPNAME = "Cardano ADA" -APPVERSION_M = 5 +APPVERSION_M = 6 APPVERSION_N = 0 APPVERSION_P = 0 APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" @@ -158,7 +158,7 @@ NANOS_ID = 1 WORDS = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" PIN = 5555 -APP_LOAD_PARAMS =--appFlags 0x240 --curve ed25519 --path "44'/1815'" --path "1852'/1815'" --path "1853'/1815'" --path "1854'/1815'" --path "1855'/1815'" +APP_LOAD_PARAMS =--appFlags 0x240 --curve ed25519 --path "44'/1815'" --path "1852'/1815'" --path "1853'/1815'" --path "1854'/1815'" --path "1855'/1815'" --path "1694'/1815'" APP_LOAD_PARAMS += $(COMMON_LOAD_PARAMS) load: all diff --git a/doc/ins_sign_catalyst_registration.md b/doc/ins_sign_catalyst_registration.md deleted file mode 100644 index b66a8288..00000000 --- a/doc/ins_sign_catalyst_registration.md +++ /dev/null @@ -1,87 +0,0 @@ -# Catalyst Voting Key Registration - -## Description - -Cardano uses a sidechain for its treasury system a.k.a. Catalyst. One needs to "register" to participate on this sidechain by submitting a registration transaction on the Cardano blockchain. This is done by submitting a transaction with specific auxiliary data attached to the transaction body. These auxiliary data contain a signature by user's staking key, hence serialization of the it by Ledger is required which after confirming by the user returns that signature for the client software to be able to assemble the full serialized transaction. - -For more details about Catalyst registration see [CIP-0015](https://github.com/cardano-foundation/CIPs/blob/master/CIP-0015/CIP-0015.md) - ---- - -In the following list of APDU messages (which are to be sent in the listed order), we only give the value of P2 and the format of message data. The general format of the message is - -|Field|Value| -|-----|-----| -| CLA | `0xD7` | -| INS | `0x21` | -| P1 | `0x08` | -| P2 | (specific for each subcall) | - -All but the last response are empty. The last response contains the overall auxiliary data hash and the signature needed for the client to assemble the Catalyst registration auxiliary data. - ---- - -**Voting key** - -P2 = `0x30` - -*Data* - -|Field| Length | Comments| -|-----|--------|---------| -|Voting public key | 32 | | - ---- - -**Staking key** - -P2 = `0x31` - -*Data* - -|Field| Length | Comments| -|-----|--------|---------| -|staking key path | variable | BIP44 path. See [GetExtPubKey call](ins_get_extended_public_key.md) for a format example | - ---- - -**Voting rewards address** - -P2 = `0x32` - -*Data* - -|Field| Length | Comments| -|-----|--------|--------| -|Address params | variable | see `view_parseAddressParams` in [src/addressUtilsShelley.c](../src/addressUtilsShelley.c)| - -Note: Only Shelley-era address parameters are accepted. - ---- - -**Nonce** - -P2 = `0x33` - -*Data* - -|Field| Length | Comments| -|-----|--------|--------| -|Nonce| 8| Big endian| - ---- - -**Confirmation** - -P2 = `0x34` - -Data must be empty. - -**Response** - -|Field|Length| Comments| -|-----|-----|-----| -| Auxiliary data hash | 32 | Hash of the Catalyst registration auxiliary data| -| Signature |64| Catalyst registration signature by the staking key that has been supplied| - -Note: Catalyst registration auxiliary data is serialized in the [Mary-era format](https://github.com/input-output-hk/cardano-ledger-specs/blob/dcdbc38eb9caea16485827bd095d5adcdcca0aba/shelley-ma/shelley-ma-test/cddl-files/shelley-ma.cddl#L214), where the array of auxiliary scripts is fixed to an empty array. diff --git a/doc/ins_sign_governance_voting_registration.md b/doc/ins_sign_governance_voting_registration.md new file mode 100644 index 00000000..4e12d963 --- /dev/null +++ b/doc/ins_sign_governance_voting_registration.md @@ -0,0 +1,145 @@ +# Governance Voting Key Registration + +## Description + +Cardano uses a sidechain for its governance voting. One needs to "register" to participate on this sidechain by submitting a registration transaction on the Cardano blockchain. This is done by submitting a transaction with specific auxiliary data attached to the transaction body. These auxiliary data contain a signature by user's staking key, hence serialization of the it by Ledger is required which after confirming by the user returns that signature for the client software to be able to assemble the full serialized transaction. + +For more details about governance voting registration see [CIP-0036](https://cips.cardano.org/cips/cip36/). + +--- + +In the following list of APDU messages (which are to be sent in the listed order), we only give the value of P2 and the format of message data. The general format of the message is + +|Field|Value| +|-----|-----| +| CLA | `0xD7` | +| INS | `0x21` | +| P1 | `0x08` | +| P2 | (specific for each subcall) | + +All but the last response are empty. The last response contains the overall auxiliary data hash and the signature needed for the client to assemble the governance voting registration auxiliary data. + +--- + +**Init** + +P2 = `0x36` + +*Data* + +|Field| Length | Comments| +|-----|--------|---------| +|Governance voting registration format | 1 | 0x01 or 0x02 for CIP15 and CIP36, respectively| +|Number of delegations | 4 | big endian | + +--- + +**Voting key** + +A single APDU with voting key is sent if the number of delegations specified in the init APDU is 0 (otherwise no such APDU is allowed). + +P2 = `0x30` + +*Data* + +|Field| Length | Comments| +|-----|--------|---------| +|Key type | 1 | 0x01 or 0x02 if a 32-byte key or its derivation path follows | +|Voting public key: bytestring or BIP44 derivation path | | (depends on previous line) | + + +**Delegation** + +The number of delegation APDUs must be equal to the number of delegations specified in the init APDU. + +P2 = `0x37` + +*Data* + +|Field| Length | Comments| +|-----|--------|---------| +|Key type | 1 | 0x01 or 0x02 if a 32-byte key or its derivation path follows | +|Voting public key: bytestring or BIP44 derivation path | | (depends on previous line) | +|Weight | 4 | big endian | + +--- + +**Staking key** + +P2 = `0x31` + +*Data* + +|Field| Length | Comments| +|-----|--------|---------| +|staking key path | variable | BIP44 path. See [GetExtPubKey call](ins_get_extended_public_key.md) for a format example | + +--- + +**Voting rewards address** + +P2 = `0x32` + +There are two possibilities for sending the address: as a bytestring (third-party) or via address parameters (device-owned). + +*Data for DESTINATION_THIRD_PARTY* + +|Field| Length | Comments| +|-----|--------|---------| +|Output type| 1 | `DESTINATION_THIRD_PARTY=0x01`| +|Address size| 4 | Big endian| +|Address| variable | raw address (before bech32/base58-encoding)| + +*Data for DESTINATION_DEVICE_OWNED* + +|Field| Length | Comments| +|-----|--------|---------| +|Output type| 1 | `DESTINATION_DEVICE_OWNED=0x02`| +|Address params | variable | see `view_parseAddressParams` in [src/addressUtilsShelley.c](../src/addressUtilsShelley.c)| + +Note: Only Shelley-era addresses are accepted (not Byron ones). + +--- + +**Nonce** + +P2 = `0x33` + +*Data* + +|Field| Length | Comments| +|-----|--------|--------| +|Nonce| 8| Big endian| + +--- + +**Voting purpose** + +For CIP36, this is optional; if not sent, voting purpose is set to the default 0. + +For CIP15, this is not allowed (and no voting purpose is serialized). + +P2 = `0x35` + +*Data* + +|Field | Length | Comments | +|--------------|--------|-----------| +|Voting purpose| 8| Big endian| + +--- + +**Confirmation** + +P2 = `0x34` + +Data must be empty. + +**Response** + +|Field|Length| Comments| +|-----|-----|-----| +| Auxiliary data hash | 32 | Hash of the governance voting registration auxiliary data| +| Signature |64| Governance voting registration signature by the staking key that has been supplied| + +Note: governance voting registration auxiliary data is serialized in the [Mary-era format](https://github.com/input-output-hk/cardano-ledger-specs/blob/dcdbc38eb9caea16485827bd095d5adcdcca0aba/shelley-ma/shelley-ma-test/cddl-files/shelley-ma.cddl#L214), where the array of auxiliary scripts is fixed to an empty array. diff --git a/doc/ins_sign_tx.md b/doc/ins_sign_tx.md index ed006890..3abd027e 100644 --- a/doc/ins_sign_tx.md +++ b/doc/ins_sign_tx.md @@ -86,7 +86,7 @@ Optional. |Field|Value| |-----|-----| | P1 | `0x08` | -| P2 | (unused / see [Catalyst Registration](ins_sign_catalyst_registration.md)) | +| P2 | (unused / see [Governance Voting Registration](ins_sign_governance_voting_registration.md)) | **Data for AUX_DATA_TYPE_ARBITRARY_HASH** @@ -98,13 +98,13 @@ So only the hash is transferred and displayed and the user has to use other mean | Auxiliary data type | 1 | `AUX_DATA_TYPE_ARBITRARY_HASH=0x00` | | Auxiliary data hash | 32 | | -**Data for AUX_DATA_TYPE_CATALYST_REGISTRATION** +**Data for AUX_DATA_TYPE_GOVERNANCE_VOTING_REGISTRATION** |Field| Length | Comments| |-----|--------|---------| -| Auxiliary data type | 1 | `AUX_DATA_TYPE_CATALYST_REGISTRATION=0x01` | +| Auxiliary data type | 1 | `AUX_DATA_TYPE_GOVERNANCE_VOTING_REGISTRATION=0x01` | -This only describes the initial message. All the data for this type of auxiliary data are obtained via a series of additional APDU messages; see [Catalyst Registration](ins_sign_catalyst_registration.md) for the details. +This only describes the initial message. All the data for this type of auxiliary data are obtained via a series of additional APDU messages; see [Governance Voting Registration](ins_sign_governance_voting_registration.md) for the details. ### Set UTxO inputs @@ -134,28 +134,28 @@ For each output, at least two messages are required: the first one with top-leve |-----|-----| | P1 | `0x03` | | P2 | `0x30` | -| data | depends on output type | +| data | depends on output destination type | -*Data for SIGN_TX_OUTPUT_TYPE_ADDRESS_BYTES* +*Data for DESTINATION_THIRD_PARTY* This output type is used for regular destination addresses. |Field| Length | Comments| |-----|--------|---------| -|Output type| 1 | `SIGN_TX_OUTPUT_TYPE_ADDRESS_BYTES=0x01`| +|Output type| 1 | `DESTINATION_THIRD_PARTY=0x01`| |Address size| 4 | Big endian| |Address| variable | raw address (before bech32/base58-encoding)| |Amount| 8| Big endian. Amount in Lovelace| |Number of asset groups| 4 | Big endian| -*Data for SIGN_TX_OUTPUT_TYPE_ADDRESS_PARAMS* +*Data for DESTINATION_DEVICE_OWNED* This output type is used for change addresses. Depending (mostly) on staking info, these might or might not be shown to the user. (See [src/securityPolicy.c](../src/securityPolicy.c) for details.) |Field| Length | Comments| |-----|--------|---------| -|Output type| 1 | `SIGN_TX_OUTPUT_TYPE_ADDRESS_PARAMS=0x02`| +|Output type| 1 | `DESTINATION_DEVICE_OWNED=0x02`| |Address params | variable | see `view_parseAddressParams` in [src/addressUtilsShelley.c](../src/addressUtilsShelley.c)| |Amount| 8| Big endian. Amount in Lovelace| |Number of asset groups| 4 | Big endian| diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt index 8d8f699f..cbe1e9a8 100644 --- a/fuzz/CMakeLists.txt +++ b/fuzz/CMakeLists.txt @@ -96,7 +96,7 @@ set(SOURCES ../src/signTxOutput.c ../src/state.c ../src/signTxPoolRegistration.c - ../src/signTxCatalystRegistration.c + ../src/signTxGovernanceVotingRegistration.c ../src/signTxUtils.c ../src/textUtils.c ../src/txHashBuilder.c diff --git a/src/addressUtilsByron_test.c b/src/addressUtilsByron_test.c index 85f48dcc..945418e5 100644 --- a/src/addressUtilsByron_test.c +++ b/src/addressUtilsByron_test.c @@ -102,7 +102,7 @@ void testProtocolMagicExtractionSucceeds() TESTCASE( "82d818584983581c9c708538a763ff27169987a489e35057ef3cd3778c05e96f7ba9450ea201581e581c9c1722f7e446689256e1a30260f3510d558d99d0c391f2ba89cb697702451a4170cb17001a6979126c", - TESTNET_PROTOCOL_MAGIC + TESTNET_PROTOCOL_MAGIC_LEGACY ); TESTCASE( diff --git a/src/auxDataHashBuilder.c b/src/auxDataHashBuilder.c index 2de2d13e..f69220c7 100644 --- a/src/auxDataHashBuilder.c +++ b/src/auxDataHashBuilder.c @@ -18,7 +18,7 @@ enum { HC_AUX_DATA = (1u << 0), // aux data hash context - HC_CATALYST_PAYLOAD = (1u << 1) // catalyst voting registration payload hash context + HC_GOVERNANCE_VOTING_PAYLOAD = (1u << 1) // governance voting registration payload hash context }; /* @@ -31,16 +31,16 @@ The following macros and functions have dual purpose: if (hashContexts & HC_AUX_DATA) { \ blake2b_256_append_cbor_aux_data(&builder->auxDataHash, type, value, true); \ } \ - if (hashContexts & HC_CATALYST_PAYLOAD) { \ - blake2b_256_append_cbor_aux_data(&builder->catalystRegistrationData.payloadHash, type, value, false); \ + if (hashContexts & HC_GOVERNANCE_VOTING_PAYLOAD) { \ + blake2b_256_append_cbor_aux_data(&builder->governanceVotingRegistrationData.payloadHash, type, value, false); \ } #define APPEND_DATA(hashContexts, buffer, bufferSize) \ if (hashContexts & HC_AUX_DATA) { \ blake2b_256_append_buffer_aux_data(&builder->auxDataHash, buffer, bufferSize, true); \ } \ - if (hashContexts & HC_CATALYST_PAYLOAD) { \ - blake2b_256_append_buffer_aux_data(&builder->catalystRegistrationData.payloadHash, buffer, bufferSize, false); \ + if (hashContexts & HC_GOVERNANCE_VOTING_PAYLOAD) { \ + blake2b_256_append_buffer_aux_data(&builder->governanceVotingRegistrationData.payloadHash, buffer, bufferSize, false); \ } @@ -83,7 +83,7 @@ void auxDataHashBuilder_init( { TRACE("Serializing tx auxiliary data"); blake2b_256_init(&builder->auxDataHash); - blake2b_256_init(&builder->catalystRegistrationData.payloadHash); + blake2b_256_init(&builder->governanceVotingRegistrationData.payloadHash); { APPEND_CBOR(HC_AUX_DATA, CBOR_TYPE_ARRAY, 2); @@ -91,36 +91,45 @@ void auxDataHashBuilder_init( builder->state = AUX_DATA_HASH_BUILDER_INIT; } -void auxDataHashBuilder_catalystRegistration_enter(aux_data_hash_builder_t* builder) +void auxDataHashBuilder_governanceVotingRegistration_enter( + aux_data_hash_builder_t* builder, + governance_voting_registration_format_t format +) { _TRACE("state = %d", builder->state); + ASSERT(format == CIP15 || format == CIP36); + builder->governanceVotingRegistrationData.format = format; + ASSERT(builder->state == AUX_DATA_HASH_BUILDER_INIT); { + // for governance voting, in the completed auxiliary data + // there is a map with two entries 61284 and 61285 APPEND_CBOR(HC_AUX_DATA, CBOR_TYPE_MAP, 2); + // however, the data being signed is a map with a single entry 61284 + APPEND_CBOR(HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_MAP, 1); + // the remainder of the payload serialization shares the cbor tokens + // with the overall auxiliary data CBOR } - builder->state = AUX_DATA_HASH_BUILDER_IN_CATALYST_REGISTRATION_INIT; + + builder->state = AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_REGISTRATION_INIT; } -void auxDataHashBuilder_catalystRegistration_enterPayload(aux_data_hash_builder_t* builder) +void auxDataHashBuilder_governanceVotingRegistration_enterPayload(aux_data_hash_builder_t* builder) { _TRACE("state = %d", builder->state); - ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_CATALYST_REGISTRATION_INIT); + ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_REGISTRATION_INIT); { - // map {61284: } is being hashed and signed in the catalyst voting registration - // this instruction introduces the beginning of this single-key dictionary - // the remainder of the payload serialization shares the tokens with the overall auxiliary data CBOR - APPEND_CBOR(HC_CATALYST_PAYLOAD, CBOR_TYPE_MAP, 1) - - // Enter the Catalyst voting key registration payload inner map - APPEND_CBOR(HC_AUX_DATA | HC_CATALYST_PAYLOAD, CBOR_TYPE_UNSIGNED, METADATA_KEY_CATALYST_REGISTRATION_PAYLOAD); - APPEND_CBOR(HC_AUX_DATA | HC_CATALYST_PAYLOAD, CBOR_TYPE_MAP, 4); + // Enter the governance voting key registration payload inner map + size_t mapSize = (builder->governanceVotingRegistrationData.format == CIP36) ? 5 : 4; + APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_UNSIGNED, METADATA_KEY_GOVERNANCE_VOTING_REGISTRATION_PAYLOAD); + APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_MAP, mapSize); } - builder->state = AUX_DATA_HASH_BUILDER_IN_CATALYST_PAYLOAD_INIT; + builder->state = AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_INIT; } -void auxDataHashBuilder_catalystRegistration_addVotingKey( +void auxDataHashBuilder_governanceVotingRegistration_addVotingKey( aux_data_hash_builder_t* builder, const uint8_t* votingPubKeyBuffer, size_t votingPubKeySize ) @@ -129,19 +138,62 @@ void auxDataHashBuilder_catalystRegistration_addVotingKey( ASSERT(votingPubKeySize < BUFFER_SIZE_PARANOIA); - ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_CATALYST_PAYLOAD_INIT); + ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_INIT); + { + APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_UNSIGNED, GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_KEY_VOTING_KEY); + { + ASSERT(votingPubKeySize == PUBLIC_KEY_SIZE); + APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_BYTES, votingPubKeySize); + APPEND_DATA(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, votingPubKeyBuffer, votingPubKeySize); + } + } + builder->state = AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_VOTING_KEY; +} + +void auxDataHashBuilder_governanceVotingRegistration_enterDelegations( + aux_data_hash_builder_t* builder, + size_t numDelegations +) +{ + _TRACE("state = %d", builder->state); + + builder->governanceVotingRegistrationData.remainingDelegations = numDelegations; + + ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_INIT); + { + APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_UNSIGNED, GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_KEY_VOTING_KEY); + APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_ARRAY, numDelegations); + } + builder->state = AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_DELEGATIONS; +} + +void auxDataHashBuilder_governanceVotingRegistration_addDelegation( + aux_data_hash_builder_t* builder, + const uint8_t* votingPubKeyBuffer, size_t votingPubKeySize, + uint32_t weight +) +{ + _TRACE("state = %d", builder->state); + + ASSERT(votingPubKeySize < BUFFER_SIZE_PARANOIA); + + ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_DELEGATIONS); + ASSERT(builder->governanceVotingRegistrationData.remainingDelegations > 0); + + builder->governanceVotingRegistrationData.remainingDelegations--; + { - APPEND_CBOR(HC_AUX_DATA | HC_CATALYST_PAYLOAD, CBOR_TYPE_UNSIGNED, CATALYST_REGISTRATION_PAYLOAD_KEY_VOTING_KEY); + APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_ARRAY, 2); { ASSERT(votingPubKeySize == PUBLIC_KEY_SIZE); - APPEND_CBOR(HC_AUX_DATA | HC_CATALYST_PAYLOAD, CBOR_TYPE_BYTES, votingPubKeySize); - APPEND_DATA(HC_AUX_DATA | HC_CATALYST_PAYLOAD, votingPubKeyBuffer, votingPubKeySize); + APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_BYTES, votingPubKeySize); + APPEND_DATA(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, votingPubKeyBuffer, votingPubKeySize); } + APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_UNSIGNED, weight); } - builder->state = AUX_DATA_HASH_BUILDER_IN_CATALYST_PAYLOAD_VOTING_KEY; } -void auxDataHashBuilder_catalystRegistration_addStakingKey( +void auxDataHashBuilder_governanceVotingRegistration_addStakingKey( aux_data_hash_builder_t* builder, const uint8_t* stakingPubKeyBuffer, size_t stakingPubKeySize ) @@ -150,69 +202,101 @@ void auxDataHashBuilder_catalystRegistration_addStakingKey( ASSERT(stakingPubKeySize < BUFFER_SIZE_PARANOIA); - ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_CATALYST_PAYLOAD_VOTING_KEY); + switch(builder->state) { + + case AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_VOTING_KEY: + // ok + break; + + case AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_DELEGATIONS: + ASSERT(builder->governanceVotingRegistrationData.remainingDelegations == 0); + break; + + default: + // should not happen + ASSERT(false); + } + { - APPEND_CBOR(HC_AUX_DATA | HC_CATALYST_PAYLOAD, CBOR_TYPE_UNSIGNED, CATALYST_REGISTRATION_PAYLOAD_KEY_STAKING_KEY); + APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_UNSIGNED, GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_KEY_STAKING_KEY); { ASSERT(stakingPubKeySize == PUBLIC_KEY_SIZE); - APPEND_CBOR(HC_AUX_DATA | HC_CATALYST_PAYLOAD, CBOR_TYPE_BYTES, stakingPubKeySize); - APPEND_DATA(HC_AUX_DATA | HC_CATALYST_PAYLOAD, stakingPubKeyBuffer, stakingPubKeySize); + APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_BYTES, stakingPubKeySize); + APPEND_DATA(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, stakingPubKeyBuffer, stakingPubKeySize); } } - builder->state = AUX_DATA_HASH_BUILDER_IN_CATALYST_PAYLOAD_STAKING_KEY; + builder->state = AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_STAKING_KEY; } -void auxDataHashBuilder_catalystRegistration_addVotingRewardsAddress( +void auxDataHashBuilder_governanceVotingRegistration_addVotingRewardsAddress( aux_data_hash_builder_t* builder, const uint8_t* addressBuffer, size_t addressSize ) { _TRACE("state = %d", builder->state); + ASSERT(addressSize > 0); ASSERT(addressSize < BUFFER_SIZE_PARANOIA); - ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_CATALYST_PAYLOAD_STAKING_KEY); - ASSERT(addressSize <= BUFFER_SIZE_PARANOIA); + ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_STAKING_KEY); { - APPEND_CBOR(HC_AUX_DATA | HC_CATALYST_PAYLOAD, CBOR_TYPE_UNSIGNED, CATALYST_REGISTRATION_PAYLOAD_KEY_VOTING_REWARDS_ADDRESS); + APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_UNSIGNED, GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_KEY_VOTING_REWARDS_ADDRESS); { - APPEND_CBOR(HC_AUX_DATA | HC_CATALYST_PAYLOAD, CBOR_TYPE_BYTES, addressSize); - APPEND_DATA(HC_AUX_DATA | HC_CATALYST_PAYLOAD, addressBuffer, addressSize); + APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_BYTES, addressSize); + APPEND_DATA(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, addressBuffer, addressSize); } } - builder->state = AUX_DATA_HASH_BUILDER_IN_CATALYST_PAYLOAD_VOTING_REWARDS_ADDRESS; + builder->state = AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_VOTING_REWARDS_ADDRESS; } -void auxDataHashBuilder_catalystRegistration_addNonce( +void auxDataHashBuilder_governanceVotingRegistration_addNonce( aux_data_hash_builder_t* builder, uint64_t nonce ) { _TRACE("state = %d", builder->state); - ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_CATALYST_PAYLOAD_VOTING_REWARDS_ADDRESS); + ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_VOTING_REWARDS_ADDRESS); + { + APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_UNSIGNED, GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_KEY_NONCE); + APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_UNSIGNED, nonce); + } + builder->state = AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_NONCE; +} + +void auxDataHashBuilder_governanceVotingRegistration_addVotingPurpose( + aux_data_hash_builder_t* builder, + uint64_t votingPurpose +) +{ + _TRACE("state = %d", builder->state); + + ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_NONCE); { - APPEND_CBOR(HC_AUX_DATA | HC_CATALYST_PAYLOAD, CBOR_TYPE_UNSIGNED, CATALYST_REGISTRATION_PAYLOAD_KEY_NONCE); - APPEND_CBOR(HC_AUX_DATA | HC_CATALYST_PAYLOAD, CBOR_TYPE_UNSIGNED, nonce); + APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_UNSIGNED, GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_KEY_VOTING_PURPOSE); + APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_UNSIGNED, votingPurpose); } - builder->state = AUX_DATA_HASH_BUILDER_IN_CATALYST_PAYLOAD_NONCE; + builder->state = AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_VOTING_PURPOSE; } -void auxDataHashBuilder_catalystRegistration_finalizePayload(aux_data_hash_builder_t* builder, uint8_t* outBuffer, size_t outSize) +void auxDataHashBuilder_governanceVotingRegistration_finalizePayload(aux_data_hash_builder_t* builder, uint8_t* outBuffer, size_t outSize) { _TRACE("state = %d", builder->state); ASSERT(outSize < BUFFER_SIZE_PARANOIA); - ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_CATALYST_PAYLOAD_NONCE); + ASSERT( + builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_NONCE || + builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_VOTING_PURPOSE + ); - ASSERT(outSize == CATALYST_REGISTRATION_PAYLOAD_HASH_LENGTH); + ASSERT(outSize == GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_HASH_LENGTH); { - blake2b_256_finalize(&builder->catalystRegistrationData.payloadHash, outBuffer, outSize); + blake2b_256_finalize(&builder->governanceVotingRegistrationData.payloadHash, outBuffer, outSize); } } -void auxDataHashBuilder_catalystRegistration_addSignature( +void auxDataHashBuilder_governanceVotingRegistration_addSignature( aux_data_hash_builder_t* builder, const uint8_t* signatureBuffer, size_t signatureSize ) @@ -221,27 +305,30 @@ void auxDataHashBuilder_catalystRegistration_addSignature( ASSERT(signatureSize < BUFFER_SIZE_PARANOIA); - ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_CATALYST_PAYLOAD_NONCE); + ASSERT( + builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_NONCE || + builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_VOTING_PURPOSE + ); { - APPEND_CBOR(HC_AUX_DATA, CBOR_TYPE_UNSIGNED, METADATA_KEY_CATALYST_SIGNATURE); + APPEND_CBOR(HC_AUX_DATA, CBOR_TYPE_UNSIGNED, METADATA_KEY_GOVERNANCE_VOTING_SIGNATURE); { ASSERT(signatureSize == ED25519_SIGNATURE_LENGTH); APPEND_CBOR(HC_AUX_DATA, CBOR_TYPE_MAP, 1); - APPEND_CBOR(HC_AUX_DATA, CBOR_TYPE_UNSIGNED, CATALYST_SIGNATURE_KEY); + APPEND_CBOR(HC_AUX_DATA, CBOR_TYPE_UNSIGNED, GOVERNANCE_VOTING_REGISTRATION_SIGNATURE_KEY); APPEND_CBOR(HC_AUX_DATA, CBOR_TYPE_BYTES, signatureSize); APPEND_DATA(HC_AUX_DATA, signatureBuffer, signatureSize); } } - builder->state = AUX_DATA_HASH_BUILDER_IN_CATALYST_SIGNATURE; + builder->state = AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_SIGNATURE; } -void auxDataHashBuilder_catalystRegistration_addAuxiliaryScripts( +void auxDataHashBuilder_governanceVotingRegistration_addAuxiliaryScripts( aux_data_hash_builder_t* builder ) { _TRACE("state = %d", builder->state); - ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_CATALYST_SIGNATURE); + ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_SIGNATURE); { // auxiliary scripts currently hard-coded to an empty list APPEND_CBOR(HC_AUX_DATA, CBOR_TYPE_ARRAY, 0); diff --git a/src/auxDataHashBuilder.h b/src/auxDataHashBuilder.h index e32710d0..c2488384 100644 --- a/src/auxDataHashBuilder.h +++ b/src/auxDataHashBuilder.h @@ -6,38 +6,48 @@ #include "keyDerivation.h" enum { - METADATA_KEY_CATALYST_REGISTRATION_PAYLOAD = 61284, - METADATA_KEY_CATALYST_SIGNATURE = 61285, + METADATA_KEY_GOVERNANCE_VOTING_REGISTRATION_PAYLOAD = 61284, + METADATA_KEY_GOVERNANCE_VOTING_SIGNATURE = 61285, }; enum { - CATALYST_REGISTRATION_PAYLOAD_KEY_VOTING_KEY = 1, - CATALYST_REGISTRATION_PAYLOAD_KEY_STAKING_KEY = 2, - CATALYST_REGISTRATION_PAYLOAD_KEY_VOTING_REWARDS_ADDRESS = 3, - CATALYST_REGISTRATION_PAYLOAD_KEY_NONCE = 4, + GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_KEY_VOTING_KEY = 1, + GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_KEY_STAKING_KEY = 2, + GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_KEY_VOTING_REWARDS_ADDRESS = 3, + GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_KEY_NONCE = 4, + GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_KEY_VOTING_PURPOSE = 5, }; enum { - CATALYST_SIGNATURE_KEY = 1, + GOVERNANCE_VOTING_REGISTRATION_SIGNATURE_KEY = 1, }; typedef enum { AUX_DATA_HASH_BUILDER_INIT = 100, - AUX_DATA_HASH_BUILDER_IN_CATALYST_REGISTRATION_INIT = 200, - AUX_DATA_HASH_BUILDER_IN_CATALYST_PAYLOAD_INIT = 210, - AUX_DATA_HASH_BUILDER_IN_CATALYST_PAYLOAD_VOTING_KEY = 211, - AUX_DATA_HASH_BUILDER_IN_CATALYST_PAYLOAD_STAKING_KEY = 212, - AUX_DATA_HASH_BUILDER_IN_CATALYST_PAYLOAD_VOTING_REWARDS_ADDRESS = 213, - AUX_DATA_HASH_BUILDER_IN_CATALYST_PAYLOAD_NONCE = 214, - AUX_DATA_HASH_BUILDER_IN_CATALYST_SIGNATURE = 220, + AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_REGISTRATION_INIT = 200, + AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_INIT = 210, + AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_VOTING_KEY = 211, + AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_DELEGATIONS = 212, + AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_STAKING_KEY = 213, + AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_VOTING_REWARDS_ADDRESS = 214, + AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_NONCE = 215, + AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_VOTING_PURPOSE = 216, + AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_SIGNATURE = 220, AUX_DATA_HASH_BUILDER_IN_AUXILIARY_SCRIPTS = 300, AUX_DATA_HASH_BUILDER_FINISHED = 400, } aux_data_hash_builder_state_t; +typedef enum { + CIP15 = 1, + CIP36 = 2 +} governance_voting_registration_format_t; + typedef struct { struct { blake2b_256_context_t payloadHash; - } catalystRegistrationData; + governance_voting_registration_format_t format; + uint16_t remainingDelegations; + } governanceVotingRegistrationData; aux_data_hash_builder_state_t state; blake2b_256_context_t auxDataHash; @@ -48,32 +58,48 @@ void auxDataHashBuilder_init( aux_data_hash_builder_t* builder ); -void auxDataHashBuilder_catalystRegistration_enter(aux_data_hash_builder_t* builder); -void auxDataHashBuilder_catalystRegistration_enterPayload(aux_data_hash_builder_t* builder); -void auxDataHashBuilder_catalystRegistration_addVotingKey( +void auxDataHashBuilder_governanceVotingRegistration_enter( + aux_data_hash_builder_t* builder, + governance_voting_registration_format_t format +); +void auxDataHashBuilder_governanceVotingRegistration_enterPayload(aux_data_hash_builder_t* builder); +void auxDataHashBuilder_governanceVotingRegistration_addVotingKey( aux_data_hash_builder_t* builder, const uint8_t* votingPubKeyBuffer, size_t votingPubKeySize ); -void auxDataHashBuilder_catalystRegistration_addStakingKey( +void auxDataHashBuilder_governanceVotingRegistration_enterDelegations( + aux_data_hash_builder_t* builder, + size_t numDelegations +); +void auxDataHashBuilder_governanceVotingRegistration_addDelegation( + aux_data_hash_builder_t* builder, + const uint8_t* votingPubKeyBuffer, size_t votingPubKeySize, + uint32_t weight +); +void auxDataHashBuilder_governanceVotingRegistration_addStakingKey( aux_data_hash_builder_t* builder, const uint8_t* stakingPubKeyBuffer, size_t stakingPubKeySize ); -void auxDataHashBuilder_catalystRegistration_addVotingRewardsAddress( +void auxDataHashBuilder_governanceVotingRegistration_addVotingRewardsAddress( aux_data_hash_builder_t* builder, const uint8_t* addressBuffer, size_t addressSize ); -void auxDataHashBuilder_catalystRegistration_addNonce(aux_data_hash_builder_t* builder, uint64_t nonce); -void auxDataHashBuilder_catalystRegistration_finalizePayload( +void auxDataHashBuilder_governanceVotingRegistration_addNonce(aux_data_hash_builder_t* builder, uint64_t nonce); +void auxDataHashBuilder_governanceVotingRegistration_addVotingPurpose( + aux_data_hash_builder_t* builder, + uint64_t votingPurpose +); +void auxDataHashBuilder_governanceVotingRegistration_finalizePayload( aux_data_hash_builder_t* builder, uint8_t* outBuffer, size_t outSize ); -void auxDataHashBuilder_catalystRegistration_addSignature( +void auxDataHashBuilder_governanceVotingRegistration_addSignature( aux_data_hash_builder_t* builder, const uint8_t* signatureBuffer, size_t signatureSize ); -void auxDataHashBuilder_catalystRegistration_addAuxiliaryScripts(aux_data_hash_builder_t* builder); +void auxDataHashBuilder_governanceVotingRegistration_addAuxiliaryScripts(aux_data_hash_builder_t* builder); void auxDataHashBuilder_finalize( aux_data_hash_builder_t* builder, diff --git a/src/auxDataHashBuilder_test.c b/src/auxDataHashBuilder_test.c index f402f042..45e4b176 100644 --- a/src/auxDataHashBuilder_test.c +++ b/src/auxDataHashBuilder_test.c @@ -6,30 +6,30 @@ #include "textUtils.h" #include "testUtils.h" +void test_CIP15() +{ + PRINTF("governance voting CIP15\n"); -static const char* votingKey = "3B40265111D8BB3C3C608D95B3A0BF83461ACE32D79336579A1939B3AAD1C0B7"; -static const char* stakingKey = "BC65BE1B0B9D7531778A1317C2AA6DE936963C3F9AC7D5EE9E9EDA25E0C97C5E"; -static const char* votingRewardsAddress = "0180F9E2C88E6C817008F3A812ED889B4A4DA8E0BD103F86E7335422AA122A946B9AD3D2DDF029D3A828F0468AECE76895F15C9EFBD69B4277"; -static uint64_t nonce = 22634813; + static const char* votingKey = "3B40265111D8BB3C3C608D95B3A0BF83461ACE32D79336579A1939B3AAD1C0B7"; + static const char* stakingKey = "BC65BE1B0B9D7531778A1317C2AA6DE936963C3F9AC7D5EE9E9EDA25E0C97C5E"; + static const char* votingRewardsAddress = "0180F9E2C88E6C817008F3A812ED889B4A4DA8E0BD103F86E7335422AA122A946B9AD3D2DDF029D3A828F0468AECE76895F15C9EFBD69B4277"; + static uint64_t nonce = 22634813; -static const char* catalystRegistrationSignature = "0EA4A424522DD485F16466CD5A754F3C8DBD4D1976C912624E3465C540B1D0776C92633FC64BE057F947AAC561012FE55ACD3C54EF7BECE0DA0B90CF02DC760D"; + static const char* governanceVotingRegistrationSignature = "0EA4A424522DD485F16466CD5A754F3C8DBD4D1976C912624E3465C540B1D0776C92633FC64BE057F947AAC561012FE55ACD3C54EF7BECE0DA0B90CF02DC760D"; -static const char* expectedCatalystVotingRegistrationPayloadHashHex = "2EEA6A5168066BDA411F80BE10B50646378616C3414C711A61D363C7879B5CBC"; -static const char* expectedAuxDataHashHex = "07cdec3a795626019739f275582433eabe32da80f82aeb74e4916b547c01a589"; + static const char* expectedGovernanceVotingRegistrationPayloadHashHex = "2EEA6A5168066BDA411F80BE10B50646378616C3414C711A61D363C7879B5CBC"; + static const char* expectedAuxDataHashHex = "07cdec3a795626019739f275582433eabe32da80f82aeb74e4916b547c01a589"; -void run_auxDataHashBuilder_test() -{ - PRINTF("auxDataHashBuilder test\n"); aux_data_hash_builder_t builder; auxDataHashBuilder_init(&builder); - auxDataHashBuilder_catalystRegistration_enter(&builder); - auxDataHashBuilder_catalystRegistration_enterPayload(&builder); + auxDataHashBuilder_governanceVotingRegistration_enter(&builder, CIP15); + auxDataHashBuilder_governanceVotingRegistration_enterPayload(&builder); { uint8_t tmp[32] = {0}; size_t tmpSize = decode_hex(votingKey, tmp, SIZEOF(tmp)); - auxDataHashBuilder_catalystRegistration_addVotingKey( + auxDataHashBuilder_governanceVotingRegistration_addVotingKey( &builder, tmp, tmpSize ); @@ -38,7 +38,7 @@ void run_auxDataHashBuilder_test() { uint8_t tmp[32] = {0}; size_t tmpSize = decode_hex(stakingKey, tmp, SIZEOF(tmp)); - auxDataHashBuilder_catalystRegistration_addStakingKey( + auxDataHashBuilder_governanceVotingRegistration_addStakingKey( &builder, tmp, tmpSize ); @@ -47,22 +47,22 @@ void run_auxDataHashBuilder_test() { uint8_t tmp[57] = {0}; size_t tmpSize = decode_hex(votingRewardsAddress, tmp, SIZEOF(tmp)); - auxDataHashBuilder_catalystRegistration_addVotingRewardsAddress( + auxDataHashBuilder_governanceVotingRegistration_addVotingRewardsAddress( &builder, tmp, tmpSize ); } - auxDataHashBuilder_catalystRegistration_addNonce(&builder, nonce); + auxDataHashBuilder_governanceVotingRegistration_addNonce(&builder, nonce); { uint8_t result[AUX_DATA_HASH_LENGTH] = {0}; - auxDataHashBuilder_catalystRegistration_finalizePayload(&builder, result, SIZEOF(result)); + auxDataHashBuilder_governanceVotingRegistration_finalizePayload(&builder, result, SIZEOF(result)); uint8_t expected[AUX_DATA_HASH_LENGTH] = {0}; - decode_hex(expectedCatalystVotingRegistrationPayloadHashHex, expected, SIZEOF(expected)); + decode_hex(expectedGovernanceVotingRegistrationPayloadHashHex, expected, SIZEOF(expected)); - PRINTF("Catalyst registration payload hash hex\n"); + PRINTF("Governance voting registration payload hash hex\n"); PRINTF("%.*h\n", 32, result); EXPECT_EQ_BYTES(result, expected, 32); @@ -70,14 +70,14 @@ void run_auxDataHashBuilder_test() { uint8_t tmp[64] = {0}; - size_t tmpSize = decode_hex(catalystRegistrationSignature, tmp, SIZEOF(tmp)); - auxDataHashBuilder_catalystRegistration_addSignature( + size_t tmpSize = decode_hex(governanceVotingRegistrationSignature, tmp, SIZEOF(tmp)); + auxDataHashBuilder_governanceVotingRegistration_addSignature( &builder, tmp, tmpSize ); } - auxDataHashBuilder_catalystRegistration_addAuxiliaryScripts(&builder); + auxDataHashBuilder_governanceVotingRegistration_addAuxiliaryScripts(&builder); { uint8_t result[AUX_DATA_HASH_LENGTH] = {0}; @@ -93,4 +93,118 @@ void run_auxDataHashBuilder_test() } } +void test_CIP36() +{ + PRINTF("governance voting CIP36\n"); + + // data from https://cips.cardano.org/cips/cip36/test-vector.md.html + + static const char* delegationKey1 = "a6a3c0447aeb9cc54cf6422ba32b294e5e1c3ef6d782f2acff4a70694c4d1663"; + static const uint64_t delegationWeight1 = 1; + static const char* delegationKey2 = "00588e8e1d18cba576a4d35758069fe94e53f638b6faf7c07b8abd2bc5c5cdee"; + static const uint64_t delegationWeight2 = 3; + + static const char* stakingKey = "86870efc99c453a873a16492ce87738ec79a0ebd064379a62e2c9cf4e119219e"; + static const char* votingRewardsAddress = "e0ae3a0a7aeda4aea522e74e4fe36759fca80789a613a58a4364f6ecef"; + static const uint64_t nonce = 1234; + static const uint64_t votingPurpose = 0; + + static const char* governanceVotingRegistrationSignature = "0ea4a424522dd485f16466cd5a754f3c8dbd4d1976c912624e3465c540b1d0776c92633fc64be057f947aac561012fe55acd3c54ef7bece0da0b90cf02dc760d"; + + static const char* expectedGovernanceVotingRegistrationPayloadHashHex = "5bc0681f173efd76e1989037a3694b8a7abea22053f5940cbb5cfcdf721007d7"; + static const char* expectedAuxDataHashHex = "3786b3ad677129e43dbb3456e45e5af589e9aae81062ef7e26f15fde00df421d"; + + aux_data_hash_builder_t builder; + + auxDataHashBuilder_init(&builder); + auxDataHashBuilder_governanceVotingRegistration_enter(&builder, CIP36); + auxDataHashBuilder_governanceVotingRegistration_enterPayload(&builder); + + auxDataHashBuilder_governanceVotingRegistration_enterDelegations(&builder, 2); + { + uint8_t tmp[32] = {0}; + size_t tmpSize = decode_hex(delegationKey1, tmp, SIZEOF(tmp)); + auxDataHashBuilder_governanceVotingRegistration_addDelegation( + &builder, + tmp, tmpSize, + delegationWeight1 + ); + } + { + uint8_t tmp[32] = {0}; + size_t tmpSize = decode_hex(delegationKey2, tmp, SIZEOF(tmp)); + auxDataHashBuilder_governanceVotingRegistration_addDelegation( + &builder, + tmp, tmpSize, + delegationWeight2 + ); + } + + { + uint8_t tmp[32] = {0}; + size_t tmpSize = decode_hex(stakingKey, tmp, SIZEOF(tmp)); + auxDataHashBuilder_governanceVotingRegistration_addStakingKey( + &builder, + tmp, tmpSize + ); + } + + { + uint8_t tmp[57] = {0}; + size_t tmpSize = decode_hex(votingRewardsAddress, tmp, SIZEOF(tmp)); + auxDataHashBuilder_governanceVotingRegistration_addVotingRewardsAddress( + &builder, + tmp, tmpSize + ); + } + + auxDataHashBuilder_governanceVotingRegistration_addNonce(&builder, nonce); + auxDataHashBuilder_governanceVotingRegistration_addVotingPurpose(&builder, votingPurpose); + + { + uint8_t result[AUX_DATA_HASH_LENGTH] = {0}; + auxDataHashBuilder_governanceVotingRegistration_finalizePayload(&builder, result, SIZEOF(result)); + + uint8_t expected[AUX_DATA_HASH_LENGTH] = {0}; + decode_hex(expectedGovernanceVotingRegistrationPayloadHashHex, expected, SIZEOF(expected)); + + PRINTF("Governance voting registration payload hash hex\n"); + PRINTF("%.*h\n", 32, result); + + EXPECT_EQ_BYTES(result, expected, 32); + } + + { + uint8_t tmp[64] = {0}; + size_t tmpSize = decode_hex(governanceVotingRegistrationSignature, tmp, SIZEOF(tmp)); + auxDataHashBuilder_governanceVotingRegistration_addSignature( + &builder, + tmp, tmpSize + ); + } + + auxDataHashBuilder_governanceVotingRegistration_addAuxiliaryScripts(&builder); + + { + uint8_t result[AUX_DATA_HASH_LENGTH] = {0}; + auxDataHashBuilder_finalize(&builder, result, SIZEOF(result)); + + uint8_t expected[AUX_DATA_HASH_LENGTH] = {0}; + decode_hex(expectedAuxDataHashHex, expected, SIZEOF(expected)); + + PRINTF("Transaction auxiliary data hash hex\n"); + PRINTF("%.*h\n", 32, result); + + EXPECT_EQ_BYTES(result, expected, 32); + } +} + +void run_auxDataHashBuilder_test() +{ + PRINTF("auxDataHashBuilder test\n"); + + test_CIP15(); + test_CIP36(); +} + #endif // DEVEL diff --git a/src/bip44.c b/src/bip44.c index 527122c6..759ae448 100644 --- a/src/bip44.c +++ b/src/bip44.c @@ -45,6 +45,12 @@ bool isHardened(uint32_t value) return value == (value | HARDENED_BIP32); } +uint32_t harden(uint32_t value) +{ + ASSERT(!isHardened(value)); + return value | HARDENED_BIP32; +} + uint32_t unharden(uint32_t value) { ASSERT(isHardened(value)); @@ -56,8 +62,8 @@ bool bip44_hasByronPrefix(const bip44_path_t* pathSpec) { #define CHECK(cond) if (!(cond)) return false CHECK(pathSpec->length > BIP44_I_COIN_TYPE); - CHECK(pathSpec->path[BIP44_I_PURPOSE] == (PURPOSE_BYRON | HARDENED_BIP32)); - CHECK(pathSpec->path[BIP44_I_COIN_TYPE] == (ADA_COIN_TYPE | HARDENED_BIP32)); + CHECK(pathSpec->path[BIP44_I_PURPOSE] == harden(PURPOSE_BYRON)); + CHECK(pathSpec->path[BIP44_I_COIN_TYPE] == harden(ADA_COIN_TYPE)); return true; #undef CHECK } @@ -67,8 +73,8 @@ bool bip44_hasShelleyPrefix(const bip44_path_t* pathSpec) { #define CHECK(cond) if (!(cond)) return false CHECK(pathSpec->length > BIP44_I_COIN_TYPE); - CHECK(pathSpec->path[BIP44_I_PURPOSE] == (PURPOSE_SHELLEY | HARDENED_BIP32)); - CHECK(pathSpec->path[BIP44_I_COIN_TYPE] == (ADA_COIN_TYPE | HARDENED_BIP32)); + CHECK(pathSpec->path[BIP44_I_PURPOSE] == harden(PURPOSE_SHELLEY)); + CHECK(pathSpec->path[BIP44_I_COIN_TYPE] == harden(ADA_COIN_TYPE)); return true; #undef CHECK } @@ -84,8 +90,8 @@ bool bip44_hasMultisigWalletKeyPrefix(const bip44_path_t* pathSpec) { #define CHECK(cond) if (!(cond)) return false CHECK(pathSpec->length > BIP44_I_COIN_TYPE); - CHECK(pathSpec->path[BIP44_I_PURPOSE] == (PURPOSE_MULTISIG | HARDENED_BIP32)); - CHECK(pathSpec->path[BIP44_I_COIN_TYPE] == (ADA_COIN_TYPE | HARDENED_BIP32)); + CHECK(pathSpec->path[BIP44_I_PURPOSE] == harden(PURPOSE_MULTISIG)); + CHECK(pathSpec->path[BIP44_I_COIN_TYPE] == harden(ADA_COIN_TYPE)); return true; #undef CHECK } @@ -95,8 +101,8 @@ bool bip44_hasMintKeyPrefix(const bip44_path_t* pathSpec) { #define CHECK(cond) if (!(cond)) return false CHECK(pathSpec->length > BIP44_I_COIN_TYPE); - CHECK(pathSpec->path[BIP44_I_PURPOSE] == (PURPOSE_MINT | HARDENED_BIP32)); - CHECK(pathSpec->path[BIP44_I_COIN_TYPE] == (ADA_COIN_TYPE | HARDENED_BIP32)); + CHECK(pathSpec->path[BIP44_I_PURPOSE] == harden(PURPOSE_MINT)); + CHECK(pathSpec->path[BIP44_I_COIN_TYPE] == harden(ADA_COIN_TYPE)); return true; #undef CHECK } @@ -106,8 +112,19 @@ bool bip44_hasPoolColdKeyPrefix(const bip44_path_t* pathSpec) { #define CHECK(cond) if (!(cond)) return false CHECK(pathSpec->length > BIP44_I_COIN_TYPE); - CHECK(pathSpec->path[BIP44_I_PURPOSE] == (PURPOSE_POOL_COLD_KEY | HARDENED_BIP32)); - CHECK(pathSpec->path[BIP44_I_COIN_TYPE] == (ADA_COIN_TYPE | HARDENED_BIP32)); + CHECK(pathSpec->path[BIP44_I_PURPOSE] == harden(PURPOSE_POOL_COLD_KEY)); + CHECK(pathSpec->path[BIP44_I_COIN_TYPE] == harden(ADA_COIN_TYPE)); + return true; +#undef CHECK +} + +// /1694'/1815' +bool bip44_hasGovernanceVotingKeyPrefix(const bip44_path_t* pathSpec) +{ +#define CHECK(cond) if (!(cond)) return false + CHECK(pathSpec->length > BIP44_I_COIN_TYPE); + CHECK(pathSpec->path[BIP44_I_PURPOSE] == harden(PURPOSE_GOVERNANCE_VOTING_KEY)); + CHECK(pathSpec->path[BIP44_I_COIN_TYPE] == harden(ADA_COIN_TYPE)); return true; #undef CHECK } @@ -137,7 +154,7 @@ uint32_t bip44_getColdKeyIndex(const bip44_path_t* pathSpec) return pathSpec->path[BIP44_I_POOL_COLD_KEY]; } -bool bip44_hasReasonableAccount(const bip44_path_t* pathSpec) +static bool bip44_hasReasonableAccount(const bip44_path_t* pathSpec) { if (!bip44_containsAccount(pathSpec)) return false; uint32_t account = bip44_getAccount(pathSpec); @@ -145,7 +162,7 @@ bool bip44_hasReasonableAccount(const bip44_path_t* pathSpec) return unharden(account) <= MAX_REASONABLE_ACCOUNT; } -bool bip44_hasReasonableMintPolicy(const bip44_path_t* pathSpec) +static bool bip44_hasReasonableMintPolicy(const bip44_path_t* pathSpec) { if (!bip44_isMintKeyPath(pathSpec)) return false; uint32_t mintPolicyIndex = bip44_getMintPolicy(pathSpec); @@ -154,7 +171,7 @@ bool bip44_hasReasonableMintPolicy(const bip44_path_t* pathSpec) return unharden(mintPolicyIndex) <= MAX_REASONABLE_MINT_POLICY_INDEX; } -bool bip44_hasReasonablePoolColdKeyIndex(const bip44_path_t* pathSpec) +static bool bip44_hasReasonablePoolColdKeyIndex(const bip44_path_t* pathSpec) { if (!bip44_isPoolColdKeyPath(pathSpec)) return false; uint32_t coldKeyIndex = bip44_getColdKeyIndex(pathSpec); @@ -176,14 +193,6 @@ uint32_t bip44_getChainTypeValue(const bip44_path_t* pathSpec) return pathSpec->path[BIP44_I_CHAIN]; } -static bool bip44_hasValidChainTypeForAddress(const bip44_path_t* pathSpec) -{ - if (!bip44_containsChainType(pathSpec)) return false; - const uint32_t chainType = bip44_getChainTypeValue(pathSpec); - - return (chainType == CARDANO_CHAIN_EXTERNAL) || (chainType == CARDANO_CHAIN_INTERNAL); -} - // Address bool bip44_containsAddress(const bip44_path_t* pathSpec) @@ -197,52 +206,44 @@ uint32_t bip44_getAddressValue(const bip44_path_t* pathSpec) return pathSpec->path[BIP44_I_ADDRESS]; } -bool bip44_hasReasonableAddress(const bip44_path_t* pathSpec) +static bool bip44_hasReasonableAddress(const bip44_path_t* pathSpec) { if (!bip44_containsAddress(pathSpec)) return false; const uint32_t address = bip44_getAddressValue(pathSpec); return (address <= MAX_REASONABLE_ADDRESS); } -// path is valid as the spending path in all addresses except REWARD -bool bip44_isOrdinarySpendingKeyPath(const bip44_path_t* pathSpec) -{ - return bip44_hasOrdinaryWalletKeyPrefix(pathSpec) && - bip44_hasValidChainTypeForAddress(pathSpec) && - bip44_containsAddress(pathSpec); -} - -bool bip44_isMultisigSpendingKeyPath(const bip44_path_t* pathSpec) +static bool bip44_containsMoreThanAddress(const bip44_path_t* pathSpec) { - return bip44_hasMultisigWalletKeyPrefix(pathSpec) && - bip44_hasValidChainTypeForAddress(pathSpec) && - bip44_containsAddress(pathSpec); + return (pathSpec->length > BIP44_I_ADDRESS + 1); } // staking keys (one per account, should end with /2/0 after account) bool bip44_isOrdinaryStakingKeyPath(const bip44_path_t* pathSpec) { - if (!bip44_containsAddress(pathSpec)) return false; - if (bip44_containsMoreThanAddress(pathSpec)) return false; - if (!bip44_hasShelleyPrefix(pathSpec)) return false; - - const uint32_t chainType = bip44_getChainTypeValue(pathSpec); - if (chainType != CARDANO_CHAIN_STAKING_KEY) return false; - - return (bip44_getAddressValue(pathSpec) == 0); +#define CHECK(cond) if (!(cond)) return false + CHECK(bip44_containsAddress(pathSpec)); + CHECK(!bip44_containsMoreThanAddress(pathSpec)); + CHECK(bip44_hasShelleyPrefix(pathSpec)); + CHECK(isHardened(bip44_getAccount(pathSpec))); + CHECK(bip44_getChainTypeValue(pathSpec) == CARDANO_CHAIN_STAKING_KEY); + CHECK(bip44_getAddressValue(pathSpec) == 0); // other values might be allowed in the future + return true; +#undef CHECK } // multisig staking keys bool bip44_isMultisigStakingKeyPath(const bip44_path_t* pathSpec) { - if (!bip44_containsAddress(pathSpec)) return false; - if (bip44_containsMoreThanAddress(pathSpec)) return false; - if (!bip44_hasMultisigWalletKeyPrefix(pathSpec)) return false; - - const uint32_t chainType = bip44_getChainTypeValue(pathSpec); - if (chainType != CARDANO_CHAIN_STAKING_KEY) return false; - +#define CHECK(cond) if (!(cond)) return false + CHECK(bip44_containsAddress(pathSpec)); + CHECK(!bip44_containsMoreThanAddress(pathSpec)); + CHECK(bip44_hasMultisigWalletKeyPrefix(pathSpec)); + CHECK(isHardened(bip44_getAccount(pathSpec))); + CHECK(bip44_getChainTypeValue(pathSpec) == CARDANO_CHAIN_STAKING_KEY); + CHECK(!isHardened(bip44_getAddressValue(pathSpec))); return true; +#undef CHECK } bool bip44_isMintKeyPath(const bip44_path_t* pathSpec) @@ -250,7 +251,7 @@ bool bip44_isMintKeyPath(const bip44_path_t* pathSpec) #define CHECK(cond) if (!(cond)) return false CHECK(pathSpec->length == BIP44_I_MINT_POLICY + 1); CHECK(bip44_hasMintKeyPrefix(pathSpec)); - CHECK(pathSpec->path[BIP44_I_MINT_POLICY] >= HARDENED_BIP32); + CHECK(isHardened(pathSpec->path[BIP44_I_MINT_POLICY])); return true; #undef CHECK } @@ -260,15 +261,22 @@ bool bip44_isPoolColdKeyPath(const bip44_path_t* pathSpec) #define CHECK(cond) if (!(cond)) return false CHECK(pathSpec->length == BIP44_I_POOL_COLD_KEY + 1); CHECK(bip44_hasPoolColdKeyPrefix(pathSpec)); - CHECK(pathSpec->path[BIP44_I_POOL_COLD_KEY_USECASE] == 0 + HARDENED_BIP32); - CHECK(pathSpec->path[BIP44_I_POOL_COLD_KEY] >= HARDENED_BIP32); + CHECK(pathSpec->path[BIP44_I_POOL_COLD_KEY_USECASE] == harden(0)); + CHECK(isHardened(pathSpec->path[BIP44_I_POOL_COLD_KEY])); return true; #undef CHECK } -bool bip44_containsMoreThanAddress(const bip44_path_t* pathSpec) +bool bip44_isGovernanceVotingKeyPath(const bip44_path_t* pathSpec) { - return (pathSpec->length > BIP44_I_ADDRESS + 1); +#define CHECK(cond) if (!(cond)) return false + CHECK(pathSpec->length == BIP44_I_ADDRESS + 1); + CHECK(bip44_hasGovernanceVotingKeyPrefix(pathSpec)); + CHECK(bip44_getAccount(pathSpec) >= HARDENED_BIP32); + CHECK(pathSpec->path[BIP44_I_CHAIN] == 0); // in the future, more might be allowed + CHECK(!isHardened(bip44_getAddressValue(pathSpec))); + return true; +#undef CHECK } // returns the length of the resulting string @@ -306,8 +314,8 @@ size_t bip44_printToStr(const bip44_path_t* pathSpec, char* out, size_t outSize) for (size_t i = 0; i < pathSpec->length; i++) { const uint32_t value = pathSpec->path[i]; - if ((value & HARDENED_BIP32) == HARDENED_BIP32) { - WRITE("/%u'", (value & ~HARDENED_BIP32)); + if (isHardened(value)) { + WRITE("/%u'", unharden(value)); } else { WRITE("/%u", value); } @@ -403,6 +411,32 @@ static bip44_path_type_t bip44_classifyMultisigWalletPath(const bip44_path_t* pa } } +static bip44_path_type_t bip44_classifyGovernanceVotingPath(const bip44_path_t* pathSpec) +{ + ASSERT(bip44_hasGovernanceVotingKeyPrefix(pathSpec)); + + // account must be hardened + if (!bip44_containsAccount(pathSpec)) { + return PATH_INVALID; + } + if (!isHardened(bip44_getAccount(pathSpec))) { + return PATH_INVALID; + } + + switch (pathSpec->length) { + case 3: { + return PATH_GOVERNANCE_VOTING_ACCOUNT; + } + case 5: { + return bip44_isGovernanceVotingKeyPath(pathSpec) ? + PATH_GOVERNANCE_VOTING_KEY : + PATH_INVALID; + } + default: + return PATH_INVALID; + } +} + bip44_path_type_t bip44_classifyPath(const bip44_path_t* pathSpec) { if (bip44_hasOrdinaryWalletKeyPrefix(pathSpec)) { @@ -429,6 +463,10 @@ bip44_path_type_t bip44_classifyPath(const bip44_path_t* pathSpec) } } + if (bip44_hasGovernanceVotingKeyPrefix(pathSpec)) { + return bip44_classifyGovernanceVotingPath(pathSpec); + } + return PATH_INVALID; } @@ -456,6 +494,12 @@ bool bip44_isPathReasonable(const bip44_path_t* pathSpec) case PATH_POOL_COLD_KEY: return bip44_hasReasonablePoolColdKeyIndex(pathSpec); + case PATH_GOVERNANCE_VOTING_ACCOUNT: + return bip44_hasReasonableAccount(pathSpec); + + case PATH_GOVERNANCE_VOTING_KEY: + return bip44_hasReasonableAccount(pathSpec) && bip44_hasReasonableAddress(pathSpec); + default: // we are not supposed to call this for invalid paths ASSERT(false); diff --git a/src/bip44.h b/src/bip44.h index daff51fa..f1e79849 100644 --- a/src/bip44.h +++ b/src/bip44.h @@ -22,10 +22,15 @@ static const uint32_t PURPOSE_MINT = 1855; static const uint32_t PURPOSE_POOL_COLD_KEY = 1853; +static const uint32_t PURPOSE_GOVERNANCE_VOTING_KEY = 1694; + static const uint32_t ADA_COIN_TYPE = 1815; static const uint32_t HARDENED_BIP32 = ((uint32_t) 1 << 31); +bool isHardened(uint32_t value); +uint32_t harden(uint32_t value); +uint32_t unharden(uint32_t value); size_t bip44_parseFromWire( bip44_path_t* pathSpec, @@ -37,6 +42,8 @@ enum { // wallet keys: // ordinary https://cips.cardano.org/cips/cip1852/ // multisig https://cips.cardano.org/cips/cip1854/ + // governance voting keys: + // https://cips.cardano.org/cips/cip36/ BIP44_I_PURPOSE = 0, BIP44_I_COIN_TYPE = 1, BIP44_I_ACCOUNT = 2, @@ -59,30 +66,23 @@ bool bip44_hasOrdinaryWalletKeyPrefix(const bip44_path_t* pathSpec); bool bip44_hasMultisigWalletKeyPrefix(const bip44_path_t* pathSpec); bool bip44_hasMintKeyPrefix(const bip44_path_t* pathSpec); bool bip44_hasPoolColdKeyPrefix(const bip44_path_t* pathSpec); +bool bip44_hasGovernanceVotingKeyPrefix(const bip44_path_t* pathSpec); bool bip44_containsAccount(const bip44_path_t* pathSpec); uint32_t bip44_getAccount(const bip44_path_t* pathSpec); -bool bip44_hasReasonableAccount(const bip44_path_t* pathSpec); bool bip44_containsChainType(const bip44_path_t* pathSpec); bool bip44_containsAddress(const bip44_path_t* pathSpec); -bool bip44_isOrdinarySpendingKeyPath(const bip44_path_t* pathSpec); -bool bip44_isMultisigSpendingKeyPath(const bip44_path_t* pathSpec); -bool bip44_hasReasonableAddress(const bip44_path_t* pathSpec); bool bip44_isOrdinaryStakingKeyPath(const bip44_path_t* pathSpec); bool bip44_isMultisigStakingKeyPath(const bip44_path_t* pathSpec); -bool bip44_containsMoreThanAddress(const bip44_path_t* pathSpec); - bool bip44_isMintKeyPath(const bip44_path_t* pathSpec); bool bip44_isPoolColdKeyPath(const bip44_path_t* pathSpec); -bool bip44_hasReasonablePoolColdKeyIndex(const bip44_path_t* pathSpec); -bool isHardened(uint32_t value); -uint32_t unharden(uint32_t value); +bool bip44_isGovernanceVotingKeyPath(const bip44_path_t* pathSpec); size_t bip44_printToStr(const bip44_path_t*, char* out, size_t outSize); @@ -106,6 +106,10 @@ typedef enum { // pool cold key in pool registrations and retirements PATH_POOL_COLD_KEY, + // governance voting, incl. Catalyst + PATH_GOVERNANCE_VOTING_ACCOUNT, + PATH_GOVERNANCE_VOTING_KEY, + // none of the above PATH_INVALID, } bip44_path_type_t; diff --git a/src/cardano.h b/src/cardano.h index 186ce83f..84fbd46b 100644 --- a/src/cardano.h +++ b/src/cardano.h @@ -19,7 +19,7 @@ STATIC_ASSERT(LOVELACE_MAX_SUPPLY < LOVELACE_INVALID, "bad LOVELACE_INVALID"); #define TX_HASH_LENGTH 32 #define AUX_DATA_HASH_LENGTH 32 #define POOL_METADATA_HASH_LENGTH 32 -#define CATALYST_REGISTRATION_PAYLOAD_HASH_LENGTH 32 +#define GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_HASH_LENGTH 32 #define ED25519_SIGNATURE_LENGTH 64 #define SCRIPT_HASH_LENGTH 28 #define SCRIPT_DATA_HASH_LENGTH 32 @@ -46,11 +46,14 @@ STATIC_ASSERT(LOVELACE_MAX_SUPPLY < LOVELACE_INVALID, "bad LOVELACE_INVALID"); #define MAX_HUMAN_ADDRESS_SIZE 150 #define MAX_HUMAN_REWARD_ACCOUNT_SIZE 65 -#define MAINNET_PROTOCOL_MAGIC 764824073 #define MAINNET_NETWORK_ID 1 +#define MAINNET_PROTOCOL_MAGIC 764824073 -#define TESTNET_PROTOCOL_MAGIC 1097911063 +// see https://book.world.dev.cardano.org/environments.html #define TESTNET_NETWORK_ID 0 +#define TESTNET_PROTOCOL_MAGIC_LEGACY 1097911063 +#define TESTNET_PROTOCOL_MAGIC_PREPROD 1 +#define TESTNET_PROTOCOL_MAGIC_PREVIEW 2 #define MAXIMUM_NETWORK_ID 0b1111 diff --git a/src/common.h b/src/common.h index b0166340..5f7f50a7 100644 --- a/src/common.h +++ b/src/common.h @@ -5,17 +5,12 @@ #include #include -// BOLOS -#include -#include -#include - #ifdef FUZZING #define explicit_bzero(addr, size) memset((addr), 0, (size)) #endif // ours -#include "utils.h" #include "assert.h" -#include "io.h" #include "errors.h" +#include "io.h" +#include "utils.h" diff --git a/src/deriveNativeScriptHash.c b/src/deriveNativeScriptHash.c index f5c178d6..2ef7ec08 100644 --- a/src/deriveNativeScriptHash.c +++ b/src/deriveNativeScriptHash.c @@ -211,7 +211,7 @@ static void deriveScriptHash_display_ui_runStep() UI_STEP(DISPLAY_UI_STEP_RESPOND) { io_send_buf(SUCCESS, NULL, 0); - ui_displayBusy(); // displays dots, called after I/O to avoid freezing + ui_displayBusy(); // displays dots, called only after I/O to avoid freezing } UI_STEP_END(DISPLAY_UI_STEP_INVALID); diff --git a/src/getPublicKeys.c b/src/getPublicKeys.c index aca687cf..bd537ab3 100644 --- a/src/getPublicKeys.c +++ b/src/getPublicKeys.c @@ -12,6 +12,7 @@ static ins_get_keys_context_t* ctx = &(instructionState.getKeysContext); // it should be set to this value at the beginning and after a UI state machine is finished static int UI_STEP_NONE = 0; +// this is supposed to be called at the beginning of each APDU handler static inline void CHECK_STAGE(get_keys_stage_t expected) { TRACE("Checking stage... current one is %d, expected %d", ctx->stage, expected); @@ -93,7 +94,7 @@ static void getPublicKeys_respondOneKey_ui_runStep() io_send_buf(SUCCESS, (uint8_t*) &ctx->extPubKey, SIZEOF(ctx->extPubKey)); ctx->responseReadyMagic = 0; // just for safety - ui_displayBusy(); // displays dots, called after I/O to avoid freezing + ui_displayBusy(); // displays dots, called only after I/O to avoid freezing ctx->currentPath++; TRACE("Current path: %u / %u", ctx->currentPath, ctx->numPaths); diff --git a/src/handlers.c b/src/handlers.c index f5911606..07204b1a 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -13,6 +13,7 @@ #include "deriveNativeScriptHash.h" #include "signTx.h" #include "signOpCert.h" +#include "signGovernanceVote.h" // The APDU protocol uses a single-byte instruction code (INS) to specify // which command should be executed. We'll use this code to dispatch on a @@ -33,6 +34,7 @@ handler_fn_t* lookupHandler(uint8_t ins) // 0x2* - signing related CASE(0x21, signTx_handleAPDU); CASE(0x22, signOpCert_handleAPDU); + CASE(0x23, signGovernanceVote_handleAPDU); #ifdef DEVEL // 0xF* - debug_mode related diff --git a/src/hash.h b/src/hash.h index 86a69879..5a2661ee 100644 --- a/src/hash.h +++ b/src/hash.h @@ -1,6 +1,8 @@ #ifndef H_CARDANO_APP_HASH #define H_CARDANO_APP_HASH +#include + #include "common.h" // This file provides convenience functions for using firmware hashing api diff --git a/src/messageSigning.c b/src/messageSigning.c index 006eb697..5e463eb6 100644 --- a/src/messageSigning.c +++ b/src/messageSigning.c @@ -1,3 +1,5 @@ +#include + #include "messageSigning.h" #include "cardano.h" #include "keyDerivation.h" @@ -62,23 +64,23 @@ static void signRawMessageWithPath(bip44_path_t* pathSpec, } END_TRY; } -void getTxWitness(bip44_path_t* pathSpec, - const uint8_t* txHashBuffer, size_t txHashSize, - uint8_t* outBuffer, size_t outSize) +// sign the given hash by the private key derived according to the given path +void getWitness(bip44_path_t* pathSpec, + const uint8_t* hashBuffer, size_t hashSize, + uint8_t* outBuffer, size_t outSize) { - ASSERT(txHashSize == TX_HASH_LENGTH); ASSERT(outSize < BUFFER_SIZE_PARANOIA); #ifndef FUZZING - signRawMessageWithPath(pathSpec, txHashBuffer, txHashSize, outBuffer, outSize); + signRawMessageWithPath(pathSpec, hashBuffer, hashSize, outBuffer, outSize); #endif } -void getCatalystVotingRegistrationSignature(bip44_path_t* pathSpec, +void getGovernanceVotingRegistrationSignature(bip44_path_t* pathSpec, const uint8_t* payloadHashBuffer, size_t payloadHashSize, uint8_t* outBuffer, size_t outSize) { - ASSERT(payloadHashSize == CATALYST_REGISTRATION_PAYLOAD_HASH_LENGTH); + ASSERT(payloadHashSize == GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_HASH_LENGTH); ASSERT(outSize < BUFFER_SIZE_PARANOIA); #ifndef FUZZING diff --git a/src/messageSigning.h b/src/messageSigning.h index 5fd7e455..634ae289 100644 --- a/src/messageSigning.h +++ b/src/messageSigning.h @@ -3,11 +3,11 @@ #include "bip44.h" -void getTxWitness(bip44_path_t* pathSpec, - const uint8_t* txHashBuffer, size_t txHashSize, - uint8_t* outBuffer, size_t outSize); +void getWitness(bip44_path_t* pathSpec, + const uint8_t* txHashBuffer, size_t txHashSize, + uint8_t* outBuffer, size_t outSize); -void getCatalystVotingRegistrationSignature(bip44_path_t* pathSpec, +void getGovernanceVotingRegistrationSignature(bip44_path_t* pathSpec, const uint8_t* payloadHashBuffer, size_t payloadHashSize, uint8_t* outBuffer, size_t outSize); diff --git a/src/securityPolicy.c b/src/securityPolicy.c index 8df781f6..ea676bae 100644 --- a/src/securityPolicy.c +++ b/src/securityPolicy.c @@ -33,13 +33,6 @@ static inline bool is_standard_base_address(const addressParams_t* addressParams #undef CHECK } -static inline bool is_reward_address(const addressParams_t* addressParams) -{ - ASSERT(isValidAddressParams(addressParams)); - - return addressParams->type == REWARD_KEY || addressParams->type == REWARD_SCRIPT; -} - static address_type_t getDestinationAddressType(const tx_output_destination_t* destination) { switch (destination->type) { @@ -93,6 +86,9 @@ security_policy_t policyForDerivePrivateKey(const bip44_path_t* path) case PATH_POOL_COLD_KEY: + case PATH_GOVERNANCE_VOTING_ACCOUNT: + case PATH_GOVERNANCE_VOTING_KEY: + ALLOW(); break; @@ -121,24 +117,51 @@ security_policy_t policyForGetExtendedPublicKey(const bip44_path_t* pathSpec) case PATH_ORDINARY_ACCOUNT: WARN_UNLESS(bip44_isPathReasonable(pathSpec)); - // in expert mode, do not export keys without permission - PROMPT_IF(app_mode_expert()); - // show Byron paths PROMPT_UNLESS(bip44_hasShelleyPrefix(pathSpec)); + + // in expert mode, do not export keys without permission + PROMPT_IF(app_mode_expert()); // do not bother the user with confirmation --- required by LedgerLive to improve UX ALLOW(); break; + case PATH_MULTISIG_ACCOUNT: + WARN_UNLESS(bip44_isPathReasonable(pathSpec)); + // ask for confirmation, multisig users need high awareness of what keys are being used + PROMPT(); + break; + + case PATH_MINT_KEY: + WARN_UNLESS(bip44_isPathReasonable(pathSpec)); + // used rarely, so making the user aware of the export does not hamper him + // but could be relaxed to expert mode if needed + PROMPT(); + break; + + case PATH_POOL_COLD_KEY: + WARN_UNLESS(bip44_isPathReasonable(pathSpec)); + // used rarely, so making the user aware of the export does not hamper him + // but could be relaxed to expert mode if needed + PROMPT(); + break; + + case PATH_GOVERNANCE_VOTING_ACCOUNT: + WARN_UNLESS(bip44_isPathReasonable(pathSpec)); + + // in expert mode, do not export keys without permission + PROMPT_IF(app_mode_expert()); + // do not bother the user with confirmation, similar to ordinary account + ALLOW(); + break; + case PATH_ORDINARY_SPENDING_KEY: case PATH_ORDINARY_STAKING_KEY: - case PATH_MULTISIG_ACCOUNT: case PATH_MULTISIG_SPENDING_KEY: case PATH_MULTISIG_STAKING_KEY: - case PATH_MINT_KEY: - case PATH_POOL_COLD_KEY: + case PATH_GOVERNANCE_VOTING_KEY: WARN_UNLESS(bip44_isPathReasonable(pathSpec)); - // ask for permission + // ask for permission (it is unusual if client asks this instead of the account key) PROMPT(); break; @@ -162,6 +185,8 @@ security_policy_t policyForGetExtendedPublicKeyBulkExport(const bip44_path_t* pa case PATH_MULTISIG_SPENDING_KEY: case PATH_MULTISIG_STAKING_KEY: case PATH_MINT_KEY: + case PATH_GOVERNANCE_VOTING_ACCOUNT: + case PATH_GOVERNANCE_VOTING_KEY: WARN_UNLESS(bip44_isPathReasonable(pathSpec)); // we do not show these paths since there may be many of them ALLOW(); @@ -250,11 +275,18 @@ security_policy_t policyForShowDeriveAddress(const addressParams_t* addressParam // true iff network is the standard mainnet or testnet bool isNetworkUsual(uint32_t networkId, uint32_t protocolMagic) { - if (networkId == MAINNET_NETWORK_ID && protocolMagic == MAINNET_PROTOCOL_MAGIC) + if (networkId == MAINNET_NETWORK_ID && protocolMagic == MAINNET_PROTOCOL_MAGIC) { return true; + } + + const bool knownTestnetProtocolMagic = + protocolMagic == TESTNET_PROTOCOL_MAGIC_LEGACY || + protocolMagic == TESTNET_PROTOCOL_MAGIC_PREPROD || + protocolMagic == TESTNET_PROTOCOL_MAGIC_PREVIEW; - if (networkId == TESTNET_NETWORK_ID && protocolMagic == TESTNET_PROTOCOL_MAGIC) + if (networkId == TESTNET_NETWORK_ID && knownTestnetProtocolMagic) { return true; + } return false; } @@ -1509,10 +1541,10 @@ security_policy_t policyForSignTxAuxData(aux_data_type_t auxDataType) SHOW_IF(app_mode_expert()); ALLOW(); - case AUX_DATA_TYPE_CATALYST_REGISTRATION: + case AUX_DATA_TYPE_GOVERNANCE_VOTING_REGISTRATION: // this is the policy for the initial prompt // details of the registration are governed by separate policies - // (see policyForCatalystRegistration...) + // (see policyForGovernanceVotingRegistration...) SHOW(); break; @@ -1724,41 +1756,95 @@ security_policy_t policyForSignTxConfirm() PROMPT(); } -security_policy_t policyForCatalystRegistrationVotingRewardsAddressParams( - const addressParams_t* params, - const uint8_t networkId -) +security_policy_t policyForGovernanceVotingRegistrationVotingKey() { - DENY_UNLESS(isValidAddressParams(params)); - DENY_UNLESS(isShelleyAddressType(params->type)); - DENY_IF(params->networkId != networkId); + SHOW(); +} - WARN_UNLESS(is_reward_address(params) || is_standard_base_address(params)); +security_policy_t policyForGovernanceVotingRegistrationVotingKeyPath( + bip44_path_t* path, + governance_voting_registration_format_t format +) +{ + // encourages people to use the new format, + // so that we can drop support for CIP15 sooner + DENY_UNLESS(format == CIP36); + DENY_UNLESS(bip44_classifyPath(path) == PATH_GOVERNANCE_VOTING_KEY); + WARN_UNLESS(bip44_isPathReasonable(path)); SHOW(); } -security_policy_t policyForCatalystRegistrationStakingKey( +security_policy_t policyForGovernanceVotingRegistrationStakingKey( const bip44_path_t* stakingKeyPath ) { DENY_UNLESS(bip44_isOrdinaryStakingKeyPath(stakingKeyPath)); - WARN_UNLESS(bip44_hasReasonableAccount(stakingKeyPath)); + WARN_UNLESS(bip44_isPathReasonable(stakingKeyPath)); SHOW(); } -security_policy_t policyForCatalystRegistrationVotingKey() +// based on https://input-output-rnd.slack.com/archives/C036XSMFXE3/p1668185230182239 +// TODO make sure this is what we want +security_policy_t policyForGovernanceVotingRegistrationVotingRewardsDestination( + const tx_output_destination_storage_t* destination, + const uint8_t networkId +) { - SHOW(); + switch (destination->type) { + + case DESTINATION_DEVICE_OWNED: { + DENY_UNLESS(isValidAddressParams(&destination->params)); + DENY_UNLESS(isShelleyAddressType(destination->params.type)); + DENY_IF(destination->params.networkId != networkId); + + // in a typical case, the rewards go to an address controlled by this device + // and the address is sent in a way allowing a verification of that fact + WARN_UNLESS( + is_standard_base_address(&destination->params) + ); + + // we are sure the address belongs to the device + SHOW(); + break; + } + + case DESTINATION_THIRD_PARTY: { + const uint8_t header = getAddressHeader( + destination->address.buffer, destination->address.size + ); + DENY_UNLESS(isShelleyAddressType(getAddressType(header))); + DENY_IF(getNetworkId(header) != networkId); + + // we don't know who owns the address + // to possibly avoid this warning, send the address as parameters (see above) + WARN(); + break; + } + + default: + ASSERT(false); + break; + } + + DENY(); // should not be reached + } -security_policy_t policyForCatalystRegistrationNonce() +security_policy_t policyForGovernanceVotingRegistrationNonce() { SHOW(); } -security_policy_t policyForCatalystRegistrationConfirm() +security_policy_t policyForGovernanceVotingRegistrationVotingPurpose() +{ + // since it will only be used for Catalyst, we don't show this value to non-experts + SHOW_IF(app_mode_expert()); + ALLOW(); +} + +security_policy_t policyForGovernanceVotingRegistrationConfirm() { PROMPT(); } @@ -1782,3 +1868,28 @@ security_policy_t policyForSignOpCert(const bip44_path_t* poolColdKeyPathSpec) DENY(); // should not be reached } + +security_policy_t policyForSignGovernanceVoteInit() +{ + PROMPT(); +} + +security_policy_t policyForSignGovernanceVoteConfirm() +{ + PROMPT(); +} + +security_policy_t policyForSignGovernanceVoteWitness(bip44_path_t* path) +{ + switch (bip44_classifyPath(path)) { + case PATH_GOVERNANCE_VOTING_KEY: + WARN_UNLESS(bip44_isPathReasonable(path)); + SHOW(); + break; + + + default: + DENY(); + break; + } +} diff --git a/src/securityPolicy.h b/src/securityPolicy.h index 79bf010d..7bf29396 100644 --- a/src/securityPolicy.h +++ b/src/securityPolicy.h @@ -187,15 +187,24 @@ security_policy_t policyForSignTxConfirm(); security_policy_t policyForSignOpCert(const bip44_path_t* poolColdKeyPathSpec); -security_policy_t policyForCatalystRegistrationVotingRewardsAddressParams( - const addressParams_t* params, - const uint8_t networkId +security_policy_t policyForGovernanceVotingRegistrationVotingKey(); +security_policy_t policyForGovernanceVotingRegistrationVotingKeyPath( + bip44_path_t* path, + governance_voting_registration_format_t format ); -security_policy_t policyForCatalystRegistrationStakingKey( +security_policy_t policyForGovernanceVotingRegistrationStakingKey( const bip44_path_t* stakingKeyPath ); -security_policy_t policyForCatalystRegistrationVotingKey(); -security_policy_t policyForCatalystRegistrationNonce(); -security_policy_t policyForCatalystRegistrationConfirm(); +security_policy_t policyForGovernanceVotingRegistrationVotingRewardsDestination( + const tx_output_destination_storage_t* destination, + const uint8_t networkId +); +security_policy_t policyForGovernanceVotingRegistrationNonce(); +security_policy_t policyForGovernanceVotingRegistrationVotingPurpose(); +security_policy_t policyForGovernanceVotingRegistrationConfirm(); + +security_policy_t policyForSignGovernanceVoteInit(); +security_policy_t policyForSignGovernanceVoteConfirm(); +security_policy_t policyForSignGovernanceVoteWitness(bip44_path_t* path); #endif // H_CARDANO_APP_SECURITY_POLICY diff --git a/src/signGovernanceVote.c b/src/signGovernanceVote.c new file mode 100644 index 00000000..1f99a563 --- /dev/null +++ b/src/signGovernanceVote.c @@ -0,0 +1,432 @@ +#include "messageSigning.h" +#include "securityPolicy.h" +#include "signGovernanceVote.h" +#include "signTxUtils.h" +#include "state.h" +#include "uiScreens.h" + +static ins_sign_governance_vote_context_t* ctx = &(instructionState.signGovernanceVoteContext); + +static void advanceStage() +{ + TRACE("Advancing governance voting stage from: %d", ctx->stage); + + switch (ctx->stage) { + case VOTECAST_STAGE_INIT: + if (ctx->remainingVotecastBytes == 0) { + ctx->stage = VOTECAST_STAGE_CONFIRM; + } else { + ctx->stage = VOTECAST_STAGE_CHUNK; + } + break; + + case VOTECAST_STAGE_CHUNK: + ASSERT(ctx->remainingVotecastBytes == 0); + ctx->stage = VOTECAST_STAGE_CONFIRM; + break; + + case VOTECAST_STAGE_CONFIRM: + ctx->stage = VOTECAST_STAGE_WITNESS; + break; + + case VOTECAST_STAGE_WITNESS: + ctx->stage = VOTECAST_STAGE_NONE; + ui_idle(); // we are done + break; + + case VOTECAST_STAGE_NONE: + // advanceStage() not supposed to be called after votecast processing is finished + ASSERT(false); + + default: + ASSERT(false); + + } + + TRACE("Advancing governance voting stage to: %d", ctx->stage); +} + +// this is supposed to be called at the beginning of each APDU handler +static inline void CHECK_STAGE(sign_governance_vote_stage_t expected) +{ + TRACE("Checking stage... current one is %d, expected %d", ctx->stage, expected); + VALIDATE(ctx->stage == expected, ERR_INVALID_STATE); +} + +// ============================== INIT ============================== + +enum { + HANDLE_INIT_CONFIRM_START = 100, + HANDLE_INIT_VOTE_PLAN_ID, + HANDLE_INIT_PROPOSAL_INDEX, + HANDLE_INIT_PAYLOAD_TYPE_TAG, + HANDLE_INIT_RESPOND, + HANDLE_INIT_INVALID, +}; + +static void handleInit_ui_runStep() +{ + ui_callback_fn_t* this_fn = handleInit_ui_runStep; + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + + UI_STEP(HANDLE_INIT_CONFIRM_START) { + ui_displayPrompt( + "Start new", + "governance vote?", + this_fn, + respond_with_user_reject + ); + } + UI_STEP(HANDLE_INIT_VOTE_PLAN_ID) { + ui_displayHexBufferScreen( + "Vote plan id", + ctx->votePlanId, SIZEOF(ctx->votePlanId), + this_fn + ); + } + UI_STEP(HANDLE_INIT_PROPOSAL_INDEX) { + ui_displayUint64Screen( + "Proposal index", + ctx->proposalIndex, + this_fn + ); + } + UI_STEP(HANDLE_INIT_PAYLOAD_TYPE_TAG) { + ui_displayUint64Screen( + "Payload type tag", + ctx->payloadTypeTag, + this_fn + ); + } + UI_STEP(HANDLE_INIT_RESPOND) { + respondSuccessEmptyMsg(); + advanceStage(); + } + UI_STEP_END(HANDLE_INIT_INVALID); +} + +__noinline_due_to_stack__ +void signGovernanceVote_handleInitAPDU( + const uint8_t* wireDataBuffer, size_t wireDataSize +) +{ + { + //sanity checks + CHECK_STAGE(VOTECAST_STAGE_INIT); + ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); + } + { + TRACE_BUFFER(wireDataBuffer, wireDataSize); + read_view_t view = make_read_view(wireDataBuffer, wireDataBuffer + wireDataSize); + + // parse total length of data to sign + ctx->remainingVotecastBytes = parse_u4be(&view); + TRACE("Remaining votecast bytes = %u", ctx->remainingVotecastBytes); + // we need vote plan id, proposal index, payload type tag + // and more data of unknown size for the fragment + VALIDATE(view_remainingSize(&view) > VOTE_PLAN_ID_SIZE + 1 + 1, ERR_INVALID_DATA); + + // this is only parsed to be shown in the UI, the whole chunk is passed to hash builder + STATIC_ASSERT(SIZEOF(ctx->votePlanId) == VOTE_PLAN_ID_SIZE, "wrong vote plan id size"); + view_parseBuffer(ctx->votePlanId, &view, VOTE_PLAN_ID_SIZE); + TRACE("Vote plan id:"); + TRACE_BUFFER(ctx->votePlanId, VOTE_PLAN_ID_SIZE); + + ctx->proposalIndex = parse_u1be(&view); + TRACE("Proposal index = %u", ctx->proposalIndex); + + ctx->payloadTypeTag = parse_u1be(&view); + TRACE("Payload type tag = %u", ctx->payloadTypeTag); + } + + // Check security policy + security_policy_t policy = policyForSignGovernanceVoteInit(); + ENSURE_NOT_DENIED(policy); + + { + read_view_t view = make_read_view(wireDataBuffer, wireDataBuffer + wireDataSize); + view_skipBytes(&view, 4); // skip total length of data to sign + + const size_t chunkSize = view_remainingSize(&view); + VALIDATE(chunkSize <= MAX_VOTECAST_CHUNK_SIZE, ERR_INVALID_DATA); + VALIDATE(chunkSize <= ctx->remainingVotecastBytes, ERR_INVALID_DATA); + + votecastHashBuilder_init(&ctx->votecastHashBuilder, ctx->remainingVotecastBytes); + votecastHashBuilder_chunk(&ctx->votecastHashBuilder, VIEW_REMAINING_TO_TUPLE_BUF_SIZE(&view)); + + ASSERT(ctx->remainingVotecastBytes >= chunkSize); + ctx->remainingVotecastBytes -= chunkSize; + } + + switch (policy) { +#define CASE(policy, step) case policy: {ctx->ui_step = step; break;} + CASE(POLICY_PROMPT_BEFORE_RESPONSE, HANDLE_INIT_CONFIRM_START); + CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_INIT_VOTE_PLAN_ID); + CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_INIT_RESPOND); +#undef CASE + default: + THROW(ERR_NOT_IMPLEMENTED); + } + handleInit_ui_runStep(); +} + +// ============================== VOTECAST CHUNK ============================== + +__noinline_due_to_stack__ +void signGovernanceVote_handleVotecastChunkAPDU( + const uint8_t* wireDataBuffer, size_t wireDataSize +) +{ + { + //sanity checks + CHECK_STAGE(VOTECAST_STAGE_CHUNK); + ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); + } + { + read_view_t view = make_read_view(wireDataBuffer, wireDataBuffer + wireDataSize); + size_t chunkSize = view_remainingSize(&view); + TRACE("chunkSize = %u", chunkSize); + VALIDATE(chunkSize > 0, ERR_INVALID_DATA); + VALIDATE(chunkSize <= MAX_VOTECAST_CHUNK_SIZE, ERR_INVALID_DATA); + VALIDATE(chunkSize <= ctx->remainingVotecastBytes, ERR_INVALID_DATA); + + votecastHashBuilder_chunk(&ctx->votecastHashBuilder, VIEW_REMAINING_TO_TUPLE_BUF_SIZE(&view)); + + ASSERT(ctx->remainingVotecastBytes >= chunkSize); + ctx->remainingVotecastBytes -= chunkSize; + } + + respondSuccessEmptyMsg(); + if (ctx->remainingVotecastBytes == 0) { + advanceStage(); + } +} + +// ============================== CONFIRM ============================== + +enum { + HANDLE_CONFIRM_STEP_FINAL_CONFIRM = 200, + HANDLE_CONFIRM_STEP_RESPOND, + HANDLE_CONFIRM_STEP_INVALID, +}; + +static void handleConfirm_ui_runStep() +{ + TRACE("UI step %d", ctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = handleConfirm_ui_runStep; + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + + UI_STEP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM) { + ui_displayPrompt( + "Confirm", + "vote?", + this_fn, + respond_with_user_reject + ); + } + UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { + io_send_buf(SUCCESS, ctx->votecastHash, SIZEOF(ctx->votecastHash)); + ui_displayBusy(); // displays dots, called only after I/O to avoid freezing + + advanceStage(); + } + UI_STEP_END(HANDLE_CONFIRM_STEP_INVALID); +} + +__noinline_due_to_stack__ +void signGovernanceVote_handleConfirmAPDU( + const uint8_t* wireDataBuffer MARK_UNUSED, size_t wireDataSize +) +{ + TRACE_STACK_USAGE(); + { + //sanity checks + CHECK_STAGE(VOTECAST_STAGE_CONFIRM); + ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); + } + { + // no data to receive + VALIDATE(wireDataSize == 0, ERR_INVALID_DATA); + } + + security_policy_t policy = policyForSignGovernanceVoteConfirm(); + TRACE("Policy: %d", (int) policy); + ENSURE_NOT_DENIED(policy); + + { + TRACE("Finalizing tx hash"); + + votecastHashBuilder_finalize( + &ctx->votecastHashBuilder, + ctx->votecastHash, SIZEOF(ctx->votecastHash) + ); + } + + { + // select UI step + switch (policy) { +#define CASE(POLICY, UI_STEP) case POLICY: {ctx->ui_step=UI_STEP; break;} + CASE(POLICY_PROMPT_BEFORE_RESPONSE, HANDLE_CONFIRM_STEP_FINAL_CONFIRM); + CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_CONFIRM_STEP_RESPOND); +#undef CASE + default: + THROW(ERR_NOT_IMPLEMENTED); + } + } + + handleConfirm_ui_runStep(); +} + +// ============================== WITNESS ============================== + +static void _wipeWitnessSignature() +{ + // safer not to keep the signature in memory + explicit_bzero(ctx->witnessData.signature, SIZEOF(ctx->witnessData.signature)); + respond_with_user_reject(); +} + +enum { + HANDLE_WITNESS_STEP_WARNING = 300, + HANDLE_WITNESS_STEP_DISPLAY, + HANDLE_WITNESS_STEP_CONFIRM, + HANDLE_WITNESS_STEP_RESPOND, + HANDLE_WITNESS_STEP_INVALID, +}; + +static void handleWitness_ui_runStep() +{ + TRACE("UI step %d", ctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = handleWitness_ui_runStep; + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + + UI_STEP(HANDLE_WITNESS_STEP_WARNING) { + ui_displayPaginatedText( + "WARNING:", + "unusual witness requested", + this_fn + ); + } + UI_STEP(HANDLE_WITNESS_STEP_DISPLAY) { + ui_displayPathScreen("Witness path", &ctx->witnessData.path, this_fn); + } + UI_STEP(HANDLE_WITNESS_STEP_CONFIRM) { + ui_displayPrompt( + "Sign using", + "this witness?", + this_fn, + _wipeWitnessSignature + ); + } + UI_STEP(HANDLE_WITNESS_STEP_RESPOND) { + TRACE("Sending witness data"); + TRACE_BUFFER(ctx->witnessData.signature, SIZEOF(ctx->witnessData.signature)); + io_send_buf(SUCCESS, ctx->witnessData.signature, SIZEOF(ctx->witnessData.signature)); + ui_displayBusy(); // displays dots, called only after I/O to avoid freezing + + advanceStage(); + } + UI_STEP_END(HANDLE_WITNESS_STEP_INVALID); +} + +__noinline_due_to_stack__ +void signGovernanceVote_handleWitnessAPDU( + const uint8_t* wireDataBuffer, size_t wireDataSize +) +{ + TRACE_STACK_USAGE(); + { + // sanity checks + CHECK_STAGE(VOTECAST_STAGE_WITNESS); + ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); + } + + { + // parse + TRACE_BUFFER(wireDataBuffer, wireDataSize); + + size_t parsedSize = bip44_parseFromWire(&ctx->witnessData.path, wireDataBuffer, wireDataSize); + VALIDATE(parsedSize == wireDataSize, ERR_INVALID_DATA); + + TRACE(); + BIP44_PRINTF(&ctx->witnessData.path); + PRINTF("\n"); + } + + security_policy_t policy = policyForSignGovernanceVoteWitness(&ctx->witnessData.path); + TRACE("Policy: %d", (int) policy); + ENSURE_NOT_DENIED(policy); + + { + // compute witness + TRACE("getGovernanceVoteWitness"); + TRACE("votecast hash:"); + TRACE_BUFFER(ctx->votecastHash, SIZEOF(ctx->votecastHash)); + + getWitness( + &ctx->witnessData.path, + ctx->votecastHash, SIZEOF(ctx->votecastHash), + ctx->witnessData.signature, SIZEOF(ctx->witnessData.signature) + ); + } + + { + // choose UI steps + switch (policy) { +#define CASE(POLICY, UI_STEP) case POLICY: {ctx->ui_step=UI_STEP; break;} + CASE(POLICY_PROMPT_WARN_UNUSUAL, HANDLE_WITNESS_STEP_WARNING); + CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_WITNESS_STEP_DISPLAY); + CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_WITNESS_STEP_RESPOND); +#undef CASE + default: + THROW(ERR_NOT_IMPLEMENTED); + } + } + handleWitness_ui_runStep(); +} + + +// ============================== MAIN HANDLER ============================== + +typedef void subhandler_fn_t(const uint8_t* dataBuffer, size_t dataSize); + +static subhandler_fn_t* lookup_subhandler(uint8_t p1) +{ + switch (p1) { +#define CASE(P1, HANDLER) case P1: return HANDLER; +#define DEFAULT(HANDLER) default: return HANDLER; + CASE(0x01, signGovernanceVote_handleInitAPDU); + CASE(0x02, signGovernanceVote_handleVotecastChunkAPDU); + CASE(0x03, signGovernanceVote_handleConfirmAPDU); + CASE(0x04, signGovernanceVote_handleWitnessAPDU); + DEFAULT(NULL) +#undef CASE +#undef DEFAULT + } +} + +void signGovernanceVote_handleAPDU( + uint8_t p1, + uint8_t p2, + const uint8_t* wireDataBuffer, + size_t wireDataSize, + bool isNewCall +) +{ + ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); + + if (isNewCall) { + explicit_bzero(ctx, SIZEOF(*ctx)); + ctx->stage = VOTECAST_STAGE_INIT; + } + VALIDATE(p2 == P2_UNUSED, ERR_INVALID_REQUEST_PARAMETERS); + + subhandler_fn_t* subhandler = lookup_subhandler(p1); + VALIDATE(subhandler != NULL, ERR_INVALID_REQUEST_PARAMETERS); + subhandler(wireDataBuffer, wireDataSize); +} diff --git a/src/signGovernanceVote.h b/src/signGovernanceVote.h new file mode 100644 index 00000000..2bc01df2 --- /dev/null +++ b/src/signGovernanceVote.h @@ -0,0 +1,45 @@ +#ifndef H_CARDANO_APP_SIGN_GOVERNANCE_VOTE +#define H_CARDANO_APP_SIGN_GOVERNANCE_VOTE + +#include "cardano.h" +#include "common.h" +#include "handlers.h" +#include "bip44.h" +#include "votecastHashBuilder.h" + +#define MAX_VOTECAST_CHUNK_SIZE 240 +#define VOTE_PLAN_ID_SIZE 32 + +typedef enum { + VOTECAST_STAGE_NONE = 0, + VOTECAST_STAGE_INIT = 20, + VOTECAST_STAGE_CHUNK = 40, + VOTECAST_STAGE_CONFIRM = 60, + VOTECAST_STAGE_WITNESS = 80, +} sign_governance_vote_stage_t; + +typedef struct { + sign_governance_vote_stage_t stage; + int ui_step; + size_t remainingVotecastBytes; + + votecast_hash_builder_t votecastHashBuilder; + uint8_t votecastHash[VOTECAST_HASH_LENGTH]; + + union { + struct { + uint8_t votePlanId[VOTE_PLAN_ID_SIZE]; + uint8_t proposalIndex; + uint8_t payloadTypeTag; + }; + uint8_t votecastChunk[MAX_VOTECAST_CHUNK_SIZE]; + struct { + bip44_path_t path; + uint8_t signature[ED25519_SIGNATURE_LENGTH]; + } witnessData; + }; +} ins_sign_governance_vote_context_t; + +handler_fn_t signGovernanceVote_handleAPDU; + +#endif // H_CARDANO_APP_SIGN_GOVERNANCE_VOTE diff --git a/src/signTx.c b/src/signTx.c index cdc5f997..55b9ab65 100644 --- a/src/signTx.c +++ b/src/signTx.c @@ -365,15 +365,15 @@ static inline void checkForFinishedSubmachines() } break; - case SIGN_STAGE_AUX_DATA_CATALYST_REGISTRATION_SUBMACHINE: - if (signTxCatalystRegistration_isFinished()) { + case SIGN_STAGE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_SUBMACHINE: + if (signTxGovernanceVotingRegistration_isFinished()) { TRACE(); ctx->stage = SIGN_STAGE_AUX_DATA; AUX_DATA_CTX->auxDataReceived = true; STATIC_ASSERT(SIZEOF(ctx->auxDataHash) == AUX_DATA_HASH_LENGTH, "Wrong auxiliary data hash length"); - STATIC_ASSERT(SIZEOF(AUX_DATA_CTX->stageContext.catalyst_registration_subctx.auxDataHash) == AUX_DATA_HASH_LENGTH, "Wrong auxiliary data hash length"); - memmove(ctx->auxDataHash, AUX_DATA_CTX->stageContext.catalyst_registration_subctx.auxDataHash, AUX_DATA_HASH_LENGTH); + STATIC_ASSERT(SIZEOF(AUX_DATA_CTX->stageContext.governance_voting_registration_subctx.auxDataHash) == AUX_DATA_HASH_LENGTH, "Wrong auxiliary data hash length"); + memmove(ctx->auxDataHash, AUX_DATA_CTX->stageContext.governance_voting_registration_subctx.auxDataHash, AUX_DATA_HASH_LENGTH); advanceStage(); } @@ -402,9 +402,11 @@ static inline void checkForFinishedSubmachines() } // this is supposed to be called at the beginning of each APDU handler -#define CHECK_STAGE(expected)\ - TRACE("Checking stage... current one is %d, expected %d", ctx->stage, expected);\ +static inline void CHECK_STAGE(sign_tx_stage_t expected) +{ + TRACE("Checking stage... current one is %d, expected %d", ctx->stage, expected); VALIDATE(ctx->stage == expected, ERR_INVALID_STATE); +} // ============================== INIT ============================== @@ -724,33 +726,33 @@ static void signTx_handleAuxDataArbitraryHash_ui_runStep() enum { - HANDLE_AUX_DATA_CATALYST_REGISTRATION_STEP_DISPLAY = 850, - HANDLE_AUX_DATA_CATALYST_REGISTRATION_STEP_RESPOND, - HANDLE_AUX_DATA_CATALYST_REGISTRATION_STEP_INVALID, + HANDLE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_STEP_DISPLAY = 850, + HANDLE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_STEP_RESPOND, + HANDLE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_STEP_INVALID, }; -static void signTx_handleAuxDataCatalystRegistration_ui_runStep() +static void signTx_handleAuxDataGovernanceVotingRegistration_ui_runStep() { TRACE("UI step %d", ctx->ui_step); TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTx_handleAuxDataCatalystRegistration_ui_runStep; + ui_callback_fn_t* this_fn = signTx_handleAuxDataGovernanceVotingRegistration_ui_runStep; UI_STEP_BEGIN(ctx->ui_step, this_fn); - UI_STEP(HANDLE_AUX_DATA_CATALYST_REGISTRATION_STEP_DISPLAY) { + UI_STEP(HANDLE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_STEP_DISPLAY) { ui_displayPrompt( - "Register Catalyst", + "Register governance", "voting key?", this_fn, respond_with_user_reject ); } - UI_STEP(HANDLE_AUX_DATA_CATALYST_REGISTRATION_STEP_RESPOND) { + UI_STEP(HANDLE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_STEP_RESPOND) { respondSuccessEmptyMsg(); - signTxCatalystRegistration_init(); - ctx->stage = SIGN_STAGE_AUX_DATA_CATALYST_REGISTRATION_SUBMACHINE; + signTxGovernanceVotingRegistration_init(); + ctx->stage = SIGN_STAGE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_SUBMACHINE; } - UI_STEP_END(HANDLE_AUX_DATA_CATALYST_REGISTRATION_STEP_INVALID); + UI_STEP_END(HANDLE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_STEP_INVALID); } __noinline_due_to_stack__ @@ -762,13 +764,13 @@ static void signTx_handleAuxDataAPDU(uint8_t p2, const uint8_t* wireDataBuffer, ASSERT(ctx->includeAuxData == true); // delegate to state sub-machine for stake pool registration certificate data - if (signTxCatalystRegistration_isValidInstruction(p2)) { + if (signTxGovernanceVotingRegistration_isValidInstruction(p2)) { TRACE(); - CHECK_STAGE(SIGN_STAGE_AUX_DATA_CATALYST_REGISTRATION_SUBMACHINE); + CHECK_STAGE(SIGN_STAGE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_SUBMACHINE); TRACE_STACK_USAGE(); - signTxCatalystRegistration_handleAPDU(p2, wireDataBuffer, wireDataSize); + signTxGovernanceVotingRegistration_handleAPDU(p2, wireDataBuffer, wireDataSize); return; } else { CHECK_STAGE(SIGN_STAGE_AUX_DATA); @@ -791,7 +793,7 @@ static void signTx_handleAuxDataAPDU(uint8_t p2, const uint8_t* wireDataBuffer, break; } - case AUX_DATA_TYPE_CATALYST_REGISTRATION: + case AUX_DATA_TYPE_GOVERNANCE_VOTING_REGISTRATION: break; default: @@ -820,18 +822,18 @@ static void signTx_handleAuxDataAPDU(uint8_t p2, const uint8_t* wireDataBuffer, signTx_handleAuxDataArbitraryHash_ui_runStep(); break; } - case AUX_DATA_TYPE_CATALYST_REGISTRATION: + case AUX_DATA_TYPE_GOVERNANCE_VOTING_REGISTRATION: // select UI step switch (policy) { #define CASE(POLICY, UI_STEP) case POLICY: {ctx->ui_step=UI_STEP; break;} - CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_AUX_DATA_CATALYST_REGISTRATION_STEP_DISPLAY); - CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_AUX_DATA_CATALYST_REGISTRATION_STEP_RESPOND); + CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_STEP_DISPLAY); + CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_STEP_RESPOND); #undef CASE default: THROW(ERR_NOT_IMPLEMENTED); } - signTx_handleAuxDataCatalystRegistration_ui_runStep(); + signTx_handleAuxDataGovernanceVotingRegistration_ui_runStep(); break; default: ASSERT(false); @@ -2278,7 +2280,7 @@ static void signTx_handleConfirm_ui_runStep() } UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { io_send_buf(SUCCESS, ctx->txHash, SIZEOF(ctx->txHash)); - ui_displayBusy(); // displays dots, called after I/O to avoid freezing + ui_displayBusy(); // displays dots, called only after I/O to avoid freezing advanceStage(); } @@ -2355,7 +2357,7 @@ static void signTx_handleConfirmAPDU(uint8_t p2, const uint8_t* wireDataBuffer M static void _wipeWitnessSignature() { - // safer not to keep this in memory + // safer not to keep the signature in memory explicit_bzero(WITNESS_CTX->stageData.witness.signature, SIZEOF(WITNESS_CTX->stageData.witness.signature)); respond_with_user_reject(); } @@ -2398,14 +2400,14 @@ static void signTx_handleWitness_ui_runStep() TRACE("Sending witness data"); TRACE_BUFFER(WITNESS_CTX->stageData.witness.signature, SIZEOF(WITNESS_CTX->stageData.witness.signature)); io_send_buf(SUCCESS, WITNESS_CTX->stageData.witness.signature, SIZEOF(WITNESS_CTX->stageData.witness.signature)); - ui_displayBusy(); // needs to happen after I/O + ui_displayBusy(); // displays dots, called only after I/O to avoid freezing WITNESS_CTX->currentWitness++; if (WITNESS_CTX->currentWitness == ctx->numWitnesses) { advanceStage(); } } - UI_STEP_END(HANDLE_INPUT_STEP_INVALID); + UI_STEP_END(HANDLE_WITNESS_STEP_INVALID); } __noinline_due_to_stack__ @@ -2447,12 +2449,12 @@ static void signTx_handleWitnessAPDU(uint8_t p2, const uint8_t* wireDataBuffer, { // compute witness - TRACE("getTxWitness"); + TRACE("getWitness"); TRACE("TX HASH"); TRACE_BUFFER(ctx->txHash, SIZEOF(ctx->txHash)); TRACE("END TX HASH"); - getTxWitness( + getWitness( &WITNESS_CTX->stageData.witness.path, ctx->txHash, SIZEOF(ctx->txHash), WITNESS_CTX->stageData.witness.signature, SIZEOF(WITNESS_CTX->stageData.witness.signature) @@ -2569,7 +2571,7 @@ ins_sign_tx_aux_data_context_t* accessAuxDataContext() switch (ctx->stage) { case SIGN_STAGE_AUX_DATA: - case SIGN_STAGE_AUX_DATA_CATALYST_REGISTRATION_SUBMACHINE: + case SIGN_STAGE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_SUBMACHINE: return &(ctx->txPartCtx.aux_data_ctx); default: diff --git a/src/signTx.h b/src/signTx.h index 6d55c0d8..c797df27 100644 --- a/src/signTx.h +++ b/src/signTx.h @@ -10,7 +10,7 @@ #include "signTxMint.h" #include "signTxOutput.h" #include "signTxPoolRegistration.h" -#include "signTxCatalystRegistration.h" +#include "signTxGovernanceVotingRegistration.h" #include "signTxAuxData.h" // the signing mode significantly affects restrictions on tx being signed @@ -26,7 +26,7 @@ typedef enum { SIGN_STAGE_NONE = 0, SIGN_STAGE_INIT = 23, SIGN_STAGE_AUX_DATA = 24, - SIGN_STAGE_AUX_DATA_CATALYST_REGISTRATION_SUBMACHINE = 25, + SIGN_STAGE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_SUBMACHINE = 25, SIGN_STAGE_BODY_INPUTS = 26, SIGN_STAGE_BODY_OUTPUTS = 27, SIGN_STAGE_BODY_OUTPUTS_SUBMACHINE = 28, @@ -121,7 +121,7 @@ typedef struct { aux_data_hash_builder_t auxDataHashBuilder; struct { - catalyst_registration_context_t catalyst_registration_subctx; + governance_voting_registration_context_t governance_voting_registration_subctx; } stageContext; } ins_sign_tx_aux_data_context_t; diff --git a/src/signTxAuxData.h b/src/signTxAuxData.h index 4317654e..44060eb0 100644 --- a/src/signTxAuxData.h +++ b/src/signTxAuxData.h @@ -3,7 +3,7 @@ typedef enum { AUX_DATA_TYPE_ARBITRARY_HASH = 0, - AUX_DATA_TYPE_CATALYST_REGISTRATION = 1, + AUX_DATA_TYPE_GOVERNANCE_VOTING_REGISTRATION = 1, } aux_data_type_t; #endif // H_CARDANO_APP_SIGN_TX_AUX_DATA diff --git a/src/signTxCatalystRegistration.c b/src/signTxCatalystRegistration.c deleted file mode 100644 index 3350c3b0..00000000 --- a/src/signTxCatalystRegistration.c +++ /dev/null @@ -1,635 +0,0 @@ -#include "app_mode.h" -#include "signTxCatalystRegistration.h" -#include "state.h" -#include "uiHelpers.h" -#include "signTxUtils.h" -#include "uiScreens.h" -#include "auxDataHashBuilder.h" -#include "txHashBuilder.h" -#include "textUtils.h" -#include "bufView.h" -#include "securityPolicy.h" -#include "messageSigning.h" - -static common_tx_data_t* commonTxData = &(instructionState.signTxContext.commonTxData); - -static inline catalyst_registration_context_t* accessSubContext() -{ - return &AUX_DATA_CTX->stageContext.catalyst_registration_subctx; -} - -bool signTxCatalystRegistration_isFinished() -{ - const catalyst_registration_context_t* subctx = accessSubContext(); - TRACE("Catalyst registration submachine state: %d", subctx->state); - // we are also asserting that the state is valid - switch (subctx->state) { - case STATE_CATALYST_REGISTRATION_FINISHED: - return true; - - case STATE_CATALYST_REGISTRATION_VOTING_KEY: - case STATE_CATALYST_REGISTRATION_STAKING_KEY: - case STATE_CATALYST_REGISTRATION_VOTING_REWARDS_ADDRESS: - case STATE_CATALYST_REGISTRATION_NONCE: - case STATE_CATALYST_REGISTRATION_CONFIRM: - return false; - - default: - ASSERT(false); - } -} - -void signTxCatalystRegistration_init() -{ - explicit_bzero(&AUX_DATA_CTX->stageContext, SIZEOF(AUX_DATA_CTX->stageContext)); - auxDataHashBuilder_init(&AUX_DATA_CTX->auxDataHashBuilder); - - accessSubContext()->state = STATE_CATALYST_REGISTRATION_VOTING_KEY; -} - -static inline void CHECK_STATE(sign_tx_catalyst_registration_state_t expected) -{ - TRACE("Catalyst voting registration submachine state: current %d, expected %d", accessSubContext()->state, expected); - VALIDATE(accessSubContext()->state == expected, ERR_INVALID_STATE); -} - -static inline void advanceState() -{ - catalyst_registration_context_t* subctx = accessSubContext(); - TRACE("Advancing Catalyst registration state from: %d", subctx->state); - - switch (subctx->state) { - - case STATE_CATALYST_REGISTRATION_VOTING_KEY: - subctx->state = STATE_CATALYST_REGISTRATION_STAKING_KEY; - break; - - case STATE_CATALYST_REGISTRATION_STAKING_KEY: - subctx->state = STATE_CATALYST_REGISTRATION_VOTING_REWARDS_ADDRESS; - break; - - case STATE_CATALYST_REGISTRATION_VOTING_REWARDS_ADDRESS: - subctx->state = STATE_CATALYST_REGISTRATION_NONCE; - break; - - case STATE_CATALYST_REGISTRATION_NONCE: - subctx->state = STATE_CATALYST_REGISTRATION_CONFIRM; - break; - - case STATE_CATALYST_REGISTRATION_CONFIRM: - subctx->state = STATE_CATALYST_REGISTRATION_FINISHED; - break; - - default: - ASSERT(false); - } - - TRACE("Advancing Catalyst registration state to: %d", subctx->state); -} - -// ============================== VOTING KEY ============================== - -enum { - HANDLE_VOTING_KEY_STEP_DISPLAY = 8200, - HANDLE_VOTING_KEY_STEP_RESPOND, - HANDLE_VOTING_KEY_STEP_INVALID, -}; - -static void signTxCatalystRegistration_handleVotingKey_ui_runStep() -{ - catalyst_registration_context_t* subctx = accessSubContext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTxCatalystRegistration_handleVotingKey_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_VOTING_KEY_STEP_DISPLAY) { - STATIC_ASSERT(SIZEOF(subctx->stateData.votingPubKey) == CATALYST_VOTING_PUBLIC_KEY_LENGTH, "wrong voting public key size"); - - // Jormungandr public key, hence the "ed25519_pk" prefix - // https://github.com/input-output-hk/jormungandr/blob/a057af27493d823be02480bb20258c25ff979e2a/jormungandr-lib/src/crypto/key.rs#L126 - ui_displayBech32Screen( - "Voting public key", - "ed25519_pk", - subctx->stateData.votingPubKey, CATALYST_VOTING_PUBLIC_KEY_LENGTH, - this_fn - ); - } - UI_STEP(HANDLE_VOTING_KEY_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_VOTING_KEY_STEP_INVALID); -} - -__noinline_due_to_stack__ -static void signTxCatalystRegistration_handleVotingKeyAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) -{ - { - CHECK_STATE(STATE_CATALYST_REGISTRATION_VOTING_KEY); - - ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); - } - catalyst_registration_context_t* subctx = accessSubContext(); - { - explicit_bzero(&subctx->stateData, SIZEOF(subctx->stateData)); - } - { - TRACE_BUFFER(wireDataBuffer, wireDataSize); - - { - VALIDATE(wireDataSize == SIZEOF(subctx->stateData.votingPubKey), ERR_INVALID_DATA); - read_view_t view = make_read_view(wireDataBuffer, wireDataBuffer + wireDataSize); - - STATIC_ASSERT(SIZEOF(subctx->stateData.votingPubKey) == CATALYST_VOTING_PUBLIC_KEY_LENGTH, "wrong voting public key size"); - view_parseBuffer(subctx->stateData.votingPubKey, &view, CATALYST_VOTING_PUBLIC_KEY_LENGTH); - - VALIDATE(view_remainingSize(&view) == 0, ERR_INVALID_DATA); - } - } - - security_policy_t policy = policyForCatalystRegistrationVotingKey(); - TRACE("Policy: %d", (int) policy); - ENSURE_NOT_DENIED(policy); - - { - aux_data_hash_builder_t* auxDataHashBuilder = &AUX_DATA_CTX->auxDataHashBuilder; - auxDataHashBuilder_catalystRegistration_enter(auxDataHashBuilder); - auxDataHashBuilder_catalystRegistration_enterPayload(auxDataHashBuilder); - auxDataHashBuilder_catalystRegistration_addVotingKey( - auxDataHashBuilder, subctx->stateData.votingPubKey, CATALYST_VOTING_PUBLIC_KEY_LENGTH - ); - } - - { - // select UI steps - switch (policy) { -#define CASE(POLICY, UI_STEP) case POLICY: {subctx->ui_step=UI_STEP; break;} - CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_VOTING_KEY_STEP_DISPLAY); - CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_VOTING_KEY_STEP_RESPOND); -#undef CASE - default: - THROW(ERR_NOT_IMPLEMENTED); - } - } - - signTxCatalystRegistration_handleVotingKey_ui_runStep(); -} - -// ============================== STAKING KEY ============================== - -enum { - HANDLE_STAKING_KEY_STEP_WARNING = 8300, - HANDLE_STAKING_KEY_STEP_DISPLAY, - HANDLE_STAKING_KEY_STEP_RESPOND, - HANDLE_STAKING_KEY_STEP_INVALID, -}; - -static void signTxCatalystRegistration_handleStakingKey_ui_runStep() -{ - catalyst_registration_context_t* subctx = accessSubContext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTxCatalystRegistration_handleStakingKey_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_STAKING_KEY_STEP_WARNING) { - ui_displayPaginatedText( - "Unusual request", - "Proceed with care", - this_fn - ); - } - UI_STEP(HANDLE_STAKING_KEY_STEP_DISPLAY) { - ui_displayStakingKeyScreen( - &subctx->stakingKeyPath, - this_fn - ); - } - UI_STEP(HANDLE_STAKING_KEY_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_STAKING_KEY_STEP_INVALID); -} - -__noinline_due_to_stack__ -static void signTxCatalystRegistration_handleStakingKeyAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) -{ - TRACE_STACK_USAGE(); - { - // sanity checks - CHECK_STATE(STATE_CATALYST_REGISTRATION_STAKING_KEY); - ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); - } - catalyst_registration_context_t* subctx = accessSubContext(); - { - explicit_bzero(&subctx->stakingKeyPath, SIZEOF(subctx->stakingKeyPath)); - } - { - // parse input - TRACE_BUFFER(wireDataBuffer, wireDataSize); - - read_view_t view = make_read_view(wireDataBuffer, wireDataBuffer + wireDataSize); - - view_skipBytes( - &view, - bip44_parseFromWire(&subctx->stakingKeyPath, VIEW_REMAINING_TO_TUPLE_BUF_SIZE(&view)) - ); - - VALIDATE(view_remainingSize(&view) == 0, ERR_INVALID_DATA); - - } - - security_policy_t policy = policyForCatalystRegistrationStakingKey( - &subctx->stakingKeyPath - ); - TRACE("Policy: %d", (int) policy); - ENSURE_NOT_DENIED(policy); - - { - extendedPublicKey_t extStakingPubKey; - deriveExtendedPublicKey(&subctx->stakingKeyPath, &extStakingPubKey); - auxDataHashBuilder_catalystRegistration_addStakingKey( - &AUX_DATA_CTX->auxDataHashBuilder, extStakingPubKey.pubKey, SIZEOF(extStakingPubKey.pubKey) - ); - } - - { - // select UI step - switch (policy) { -#define CASE(POLICY, UI_STEP) case POLICY: {subctx->ui_step=UI_STEP; break;} - CASE(POLICY_PROMPT_WARN_UNUSUAL, HANDLE_STAKING_KEY_STEP_WARNING); - CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_STAKING_KEY_STEP_DISPLAY); - CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_STAKING_KEY_STEP_RESPOND); -#undef CASE - default: - THROW(ERR_NOT_IMPLEMENTED); - } - } - - signTxCatalystRegistration_handleStakingKey_ui_runStep(); -} - -// ============================== VOTING REWARDS ADDRESS ============================== - -enum { - HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_WARNING = 8500, - HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS, - HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_RESPOND, - HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_INVALID -}; - -__noinline_due_to_stack__ -static void signTxCatalystRegistration_handleVotingRewardsAddress_addressParams_ui_runStep() -{ - catalyst_registration_context_t* subctx = accessSubContext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTxCatalystRegistration_handleVotingRewardsAddress_addressParams_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_WARNING) { - ui_displayPaginatedText( - "Unusual request", - "Proceed with care", - this_fn - ); - } - UI_STEP(HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS) { - uint8_t addressBuffer[MAX_ADDRESS_SIZE] = {0}; - size_t addressSize = deriveAddress( - &subctx->stateData.votingRewardsAddressParams, - addressBuffer, - SIZEOF(addressBuffer) - ); - ASSERT(addressSize > 0); - ASSERT(addressSize < BUFFER_SIZE_PARANOIA); - - ui_displayAddressScreen( - "Rewards go to", - addressBuffer, - addressSize, - this_fn - ); - } - UI_STEP(HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_INVALID); -} - -__noinline_due_to_stack__ -static void signTxCatalystRegistration_handleVotingRewardsAddressAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) -{ - { - // safety checks - CHECK_STATE(STATE_CATALYST_REGISTRATION_VOTING_REWARDS_ADDRESS); - - ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); - } - catalyst_registration_context_t* subctx = accessSubContext(); - { - explicit_bzero( - &subctx->stateData.votingRewardsAddressParams, - SIZEOF(subctx->stateData.votingRewardsAddressParams) - ); - } - { - TRACE_BUFFER(wireDataBuffer, wireDataSize); - - read_view_t view = make_read_view(wireDataBuffer, wireDataBuffer + wireDataSize); - - view_parseAddressParams(&view, &subctx->stateData.votingRewardsAddressParams); - - VALIDATE(view_remainingSize(&view) == 0, ERR_INVALID_DATA); - } - - security_policy_t policy = policyForCatalystRegistrationVotingRewardsAddressParams( - &subctx->stateData.votingRewardsAddressParams, - commonTxData->networkId - ); - TRACE("Policy: %d", (int) policy); - ENSURE_NOT_DENIED(policy); - - { - ASSERT(isShelleyAddressType(subctx->stateData.votingRewardsAddressParams.type)); - uint8_t addressBuffer[MAX_ADDRESS_SIZE] = {0}; - size_t addressSize = deriveAddress( - &subctx->stateData.votingRewardsAddressParams, - addressBuffer, - SIZEOF(addressBuffer) - ); - ASSERT(addressSize > 0); - ASSERT(addressSize < BUFFER_SIZE_PARANOIA); - - auxDataHashBuilder_catalystRegistration_addVotingRewardsAddress( - &AUX_DATA_CTX->auxDataHashBuilder, addressBuffer, addressSize - ); - } - - { - // select UI steps - switch (policy) { -#define CASE(POLICY, UI_STEP) case POLICY: {subctx->ui_step=UI_STEP; break;} - CASE(POLICY_PROMPT_WARN_UNUSUAL, HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_WARNING); - CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS); - CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_RESPOND); -#undef CASE - default: - THROW(ERR_NOT_IMPLEMENTED); - } - - signTxCatalystRegistration_handleVotingRewardsAddress_addressParams_ui_runStep(); - } -} - -// ============================== NONCE ============================== - -enum { - HANDLE_NONCE_STEP_DISPLAY = 8600, - HANDLE_NONCE_STEP_RESPOND, - HANDLE_NONCE_STEP_INVALID, -}; - -static void signTxCatalystRegistration_handleNonce_ui_runStep() -{ - catalyst_registration_context_t* subctx = accessSubContext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTxCatalystRegistration_handleNonce_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_NONCE_STEP_DISPLAY) { - ui_displayUint64Screen( - "Nonce", - subctx->stateData.nonce, - this_fn - ); - } - UI_STEP(HANDLE_NONCE_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_NONCE_STEP_INVALID); -} - -__noinline_due_to_stack__ -static void signTxCatalystRegistration_handleNonceAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) -{ - { - // sanity checks - CHECK_STATE(STATE_CATALYST_REGISTRATION_NONCE); - - ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); - } - catalyst_registration_context_t* subctx = accessSubContext(); - { - explicit_bzero(&subctx->stateData, SIZEOF(subctx->stateData)); - } - { - // parse data - TRACE_BUFFER(wireDataBuffer, wireDataSize); - VALIDATE(wireDataSize == 8, ERR_INVALID_DATA); - subctx->stateData.nonce = u8be_read(wireDataBuffer); - TRACE( - "Catalyst registration nonce: %d", - subctx->stateData.nonce - ); - } - - security_policy_t policy = policyForCatalystRegistrationNonce(); - TRACE("Policy: %d", (int) policy); - ENSURE_NOT_DENIED(policy); - - { - auxDataHashBuilder_catalystRegistration_addNonce(&AUX_DATA_CTX->auxDataHashBuilder, subctx->stateData.nonce); - } - - { - // select UI steps - switch (policy) { -#define CASE(POLICY, UI_STEP) case POLICY: {subctx->ui_step=UI_STEP; break;} - CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_NONCE_STEP_DISPLAY); - CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_NONCE_STEP_RESPOND); -#undef CASE - default: - THROW(ERR_NOT_IMPLEMENTED); - } - } - - signTxCatalystRegistration_handleNonce_ui_runStep(); -} - -// ============================== CONFIRM ============================== - -enum { - HANDLE_CONFIRM_STEP_FINAL_CONFIRM, - HANDLE_CONFIRM_STEP_DISPLAY_HASH, - HANDLE_CONFIRM_STEP_RESPOND, - HANDLE_CONFIRM_STEP_INVALID, -}; - -static void signTxCatalystRegistration_handleConfirm_ui_runStep() -{ - catalyst_registration_context_t* subctx = accessSubContext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTxCatalystRegistration_handleConfirm_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - UI_STEP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM) { - // confirming this means the signature being sent out of the device - // so we want to show it in non-expert mode too - ui_displayPrompt( - "Confirm voting key", - "registration?", - this_fn, - respond_with_user_reject - ); - } - UI_STEP(HANDLE_CONFIRM_STEP_DISPLAY_HASH) { - if (!app_mode_expert()) { - UI_STEP_JUMP(HANDLE_CONFIRM_STEP_RESPOND); - } - ui_displayHexBufferScreen( - "Auxiliary data hash", - subctx->auxDataHash, - SIZEOF(subctx->auxDataHash), - this_fn - ); - } - UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { - struct { - uint8_t auxDataHash[AUX_DATA_HASH_LENGTH]; - uint8_t signature[ED25519_SIGNATURE_LENGTH]; - } wireResponse = {0}; - - STATIC_ASSERT(SIZEOF(subctx->auxDataHash) == AUX_DATA_HASH_LENGTH, "Wrong aux data hash length"); - memmove(wireResponse.auxDataHash, subctx->auxDataHash, AUX_DATA_HASH_LENGTH); - - STATIC_ASSERT(SIZEOF(subctx->stateData.registrationSignature) == ED25519_SIGNATURE_LENGTH, "Wrong Catalyst registration signature length"); - memmove(wireResponse.signature, subctx->stateData.registrationSignature, ED25519_SIGNATURE_LENGTH); - - io_send_buf(SUCCESS, (uint8_t*) &wireResponse, SIZEOF(wireResponse)); - advanceState(); - } - UI_STEP_END(HANDLE_CONFIRM_STEP_INVALID); -} - -__noinline_due_to_stack__ -static void signTxCatalystRegistration_handleConfirmAPDU(const uint8_t* wireDataBuffer MARK_UNUSED, size_t wireDataSize) -{ - { - //sanity checks - CHECK_STATE(STATE_CATALYST_REGISTRATION_CONFIRM); - - ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); - } - catalyst_registration_context_t* subctx = accessSubContext(); - { - explicit_bzero(&subctx->stateData, SIZEOF(subctx->stateData)); - } - - { - // no data to receive - VALIDATE(wireDataSize == 0, ERR_INVALID_DATA); - } - - security_policy_t policy = policyForCatalystRegistrationConfirm(); - TRACE("Policy: %d", (int) policy); - ENSURE_NOT_DENIED(policy); - - { - aux_data_hash_builder_t* auxDataHashBuilder = &AUX_DATA_CTX->auxDataHashBuilder; - { - uint8_t votingPayloadHashBuffer[CATALYST_REGISTRATION_PAYLOAD_HASH_LENGTH] = {0}; - auxDataHashBuilder_catalystRegistration_finalizePayload(auxDataHashBuilder, votingPayloadHashBuffer, AUX_DATA_HASH_LENGTH); - getCatalystVotingRegistrationSignature( - &subctx->stakingKeyPath, - votingPayloadHashBuffer, CATALYST_REGISTRATION_PAYLOAD_HASH_LENGTH, - subctx->stateData.registrationSignature, ED25519_SIGNATURE_LENGTH - ); - } - auxDataHashBuilder_catalystRegistration_addSignature(auxDataHashBuilder, subctx->stateData.registrationSignature, ED25519_SIGNATURE_LENGTH); - auxDataHashBuilder_catalystRegistration_addAuxiliaryScripts(auxDataHashBuilder); - - auxDataHashBuilder_finalize(auxDataHashBuilder, subctx->auxDataHash, AUX_DATA_HASH_LENGTH); - } - - { - // select UI steps - switch (policy) { -#define CASE(POLICY, UI_STEP) case POLICY: {subctx->ui_step=UI_STEP; break;} - CASE(POLICY_PROMPT_BEFORE_RESPONSE, HANDLE_CONFIRM_STEP_FINAL_CONFIRM); - CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_CONFIRM_STEP_RESPOND); -#undef CASE - default: - THROW(ERR_NOT_IMPLEMENTED); - } - } - - signTxCatalystRegistration_handleConfirm_ui_runStep(); -} - - -// ============================== main APDU handler ============================== - -enum { - APDU_INSTRUCTION_VOTING_KEY = 0x30, - APDU_INSTRUCTION_STAKING_KEY = 0x31, - APDU_INSTRUCTION_VOTING_REWARDS_ADDRESS = 0x32, - APDU_INSTRUCTION_NONCE = 0x33, - APDU_INSTRUCTION_CONFIRM = 0x34 -}; - -bool signTxCatalystRegistration_isValidInstruction(uint8_t p2) -{ - switch (p2) { - case APDU_INSTRUCTION_VOTING_KEY: - case APDU_INSTRUCTION_STAKING_KEY: - case APDU_INSTRUCTION_VOTING_REWARDS_ADDRESS: - case APDU_INSTRUCTION_NONCE: - case APDU_INSTRUCTION_CONFIRM: - return true; - - default: - return false; - } -} - -void signTxCatalystRegistration_handleAPDU(uint8_t p2, const uint8_t* wireDataBuffer, size_t wireDataSize) -{ - ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); - - switch (p2) { - case APDU_INSTRUCTION_VOTING_KEY: - signTxCatalystRegistration_handleVotingKeyAPDU(wireDataBuffer, wireDataSize); - break; - - case APDU_INSTRUCTION_STAKING_KEY: - signTxCatalystRegistration_handleStakingKeyAPDU(wireDataBuffer, wireDataSize); - break; - - case APDU_INSTRUCTION_VOTING_REWARDS_ADDRESS: - signTxCatalystRegistration_handleVotingRewardsAddressAPDU(wireDataBuffer, wireDataSize); - break; - - case APDU_INSTRUCTION_NONCE: - signTxCatalystRegistration_handleNonceAPDU(wireDataBuffer, wireDataSize); - break; - - case APDU_INSTRUCTION_CONFIRM: - signTxCatalystRegistration_handleConfirmAPDU(wireDataBuffer, wireDataSize); - break; - - default: - // this is not supposed to be called with invalid p2 - ASSERT(false); - } -} diff --git a/src/signTxCatalystRegistration.h b/src/signTxCatalystRegistration.h deleted file mode 100644 index 88ff6967..00000000 --- a/src/signTxCatalystRegistration.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef H_CARDANO_APP_SIGN_TX_CATALYST_REGISTRATION -#define H_CARDANO_APP_SIGN_TX_CATALYST_REGISTRATION - -#include "common.h" -#include "cardano.h" -#include "auxDataHashBuilder.h" -#include "addressUtilsShelley.h" - - -#define CATALYST_VOTING_PUBLIC_KEY_LENGTH 32 - -// SIGN_STAGE_AUX_DATA = 24 -// AUX_DATA_TYPE_CATALYST_REGISTRATION = 1 -typedef enum { - STATE_CATALYST_REGISTRATION_VOTING_KEY = 2410, - STATE_CATALYST_REGISTRATION_STAKING_KEY = 2411, - STATE_CATALYST_REGISTRATION_VOTING_REWARDS_ADDRESS = 2412, - STATE_CATALYST_REGISTRATION_NONCE = 2413, - STATE_CATALYST_REGISTRATION_CONFIRM = 2414, - STATE_CATALYST_REGISTRATION_FINISHED = 2415 -} sign_tx_catalyst_registration_state_t; - -typedef struct { - sign_tx_catalyst_registration_state_t state; - int ui_step; - - /* - * Staking key path kept outside of stateData to produce the Catalyst registration - * signature at the end of the flow without re-requesting the staking key path - * (with the undesired side-effect of allowing signing with a different key than included - * in the registration payload) - */ - bip44_path_t stakingKeyPath; - uint8_t auxDataHash[AUX_DATA_HASH_LENGTH]; - - union { - uint8_t votingPubKey[CATALYST_VOTING_PUBLIC_KEY_LENGTH]; - addressParams_t votingRewardsAddressParams; - uint64_t nonce; - uint8_t registrationSignature[ED25519_SIGNATURE_LENGTH]; - } stateData; -} catalyst_registration_context_t; - -void signTxCatalystRegistration_init(); - -bool signTxCatalystRegistration_isValidInstruction(uint8_t p2); -void signTxCatalystRegistration_handleAPDU(uint8_t p2, const uint8_t* wireDataBuffer, size_t wireDataSize); - -bool signTxCatalystRegistration_isFinished(); - -#endif // H_CARDANO_APP_SIGN_TX_CATALYST_REGISTRATION diff --git a/src/signTxGovernanceVotingRegistration.c b/src/signTxGovernanceVotingRegistration.c new file mode 100644 index 00000000..42ad8daf --- /dev/null +++ b/src/signTxGovernanceVotingRegistration.c @@ -0,0 +1,1078 @@ +#include "app_mode.h" +#include "signTxGovernanceVotingRegistration.h" +#include "state.h" +#include "uiHelpers.h" +#include "signTxUtils.h" +#include "uiScreens.h" +#include "auxDataHashBuilder.h" +#include "txHashBuilder.h" +#include "textUtils.h" +#include "bufView.h" +#include "securityPolicy.h" +#include "messageSigning.h" + +static common_tx_data_t* commonTxData = &(instructionState.signTxContext.commonTxData); + +static inline governance_voting_registration_context_t* accessSubContext() +{ + return &AUX_DATA_CTX->stageContext.governance_voting_registration_subctx; +} + +bool signTxGovernanceVotingRegistration_isFinished() +{ + const governance_voting_registration_context_t* subctx = accessSubContext(); + TRACE("Governance voting registration submachine state: %d", subctx->state); + // we are also asserting that the state is valid + switch (subctx->state) { + case STATE_GOVERNANCE_VOTING_REGISTRATION_FINISHED: + return true; + + case STATE_GOVERNANCE_VOTING_REGISTRATION_INIT: + case STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_KEY: + case STATE_GOVERNANCE_VOTING_REGISTRATION_DELEGATIONS: + case STATE_GOVERNANCE_VOTING_REGISTRATION_STAKING_KEY: + case STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_REWARDS_ADDRESS: + case STATE_GOVERNANCE_VOTING_REGISTRATION_NONCE: + case STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_PURPOSE: + case STATE_GOVERNANCE_VOTING_REGISTRATION_CONFIRM: + return false; + + default: + ASSERT(false); + } +} + +void signTxGovernanceVotingRegistration_init() +{ + explicit_bzero(&AUX_DATA_CTX->stageContext, SIZEOF(AUX_DATA_CTX->stageContext)); + auxDataHashBuilder_init(&AUX_DATA_CTX->auxDataHashBuilder); + + accessSubContext()->state = STATE_GOVERNANCE_VOTING_REGISTRATION_INIT; +} + +static inline void CHECK_STATE(sign_tx_governance_voting_registration_state_t expected) +{ + TRACE("Governance voting registration submachine state: current %d, expected %d", accessSubContext()->state, expected); + VALIDATE(accessSubContext()->state == expected, ERR_INVALID_STATE); +} + +static inline void advanceState() +{ + governance_voting_registration_context_t* subctx = accessSubContext(); + TRACE("Advancing governance voting registration state from: %d", subctx->state); + + switch (subctx->state) { + + case STATE_GOVERNANCE_VOTING_REGISTRATION_INIT: + if (subctx->numDelegations > 0) { + subctx->state = STATE_GOVERNANCE_VOTING_REGISTRATION_DELEGATIONS; + auxDataHashBuilder_governanceVotingRegistration_enterDelegations( + &AUX_DATA_CTX->auxDataHashBuilder, + subctx->numDelegations + ); + } else { + // we expect a single voting key + subctx->state = STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_KEY; + } + break; + + case STATE_GOVERNANCE_VOTING_REGISTRATION_DELEGATIONS: + ASSERT(subctx->currentDelegation == subctx->numDelegations); + subctx->state = STATE_GOVERNANCE_VOTING_REGISTRATION_STAKING_KEY; + break; + + case STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_KEY: + subctx->state = STATE_GOVERNANCE_VOTING_REGISTRATION_STAKING_KEY; + break; + + case STATE_GOVERNANCE_VOTING_REGISTRATION_STAKING_KEY: + subctx->state = STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_REWARDS_ADDRESS; + break; + + case STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_REWARDS_ADDRESS: + subctx->state = STATE_GOVERNANCE_VOTING_REGISTRATION_NONCE; + break; + + case STATE_GOVERNANCE_VOTING_REGISTRATION_NONCE: + subctx->state = STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_PURPOSE; + break; + + case STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_PURPOSE: + subctx->state = STATE_GOVERNANCE_VOTING_REGISTRATION_CONFIRM; + break; + + case STATE_GOVERNANCE_VOTING_REGISTRATION_CONFIRM: + subctx->state = STATE_GOVERNANCE_VOTING_REGISTRATION_FINISHED; + break; + + default: + ASSERT(false); + } + + TRACE("Advancing governance voting registration state to: %d", subctx->state); +} + +// ============================== INIT ============================== + +static void signTxGovernanceVotingRegistration_handleInitAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) +{ + { + CHECK_STATE(STATE_GOVERNANCE_VOTING_REGISTRATION_INIT); + + ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); + } + governance_voting_registration_context_t* subctx = accessSubContext(); + { + explicit_bzero(&subctx->stateData, SIZEOF(subctx->stateData)); + } + { + TRACE_BUFFER(wireDataBuffer, wireDataSize); + + { + read_view_t view = make_read_view(wireDataBuffer, wireDataBuffer + wireDataSize); + + subctx->format = parse_u1be(&view); + TRACE("Governance voting registration format = %d", (int) subctx->format); + switch (subctx->format) { + case CIP15: + case CIP36: + break; + default: + THROW(ERR_INVALID_DATA); + } + + subctx->numDelegations = (uint16_t) parse_u4be(&view); + TRACE("numDelegations = %u", subctx->numDelegations); + if (subctx->format == CIP15) { + // delegations only allowed in CIP36 + VALIDATE(subctx->numDelegations == 0, ERR_INVALID_DATA); + } + + VALIDATE(view_remainingSize(&view) == 0, ERR_INVALID_DATA); + } + } + { + aux_data_hash_builder_t* auxDataHashBuilder = &AUX_DATA_CTX->auxDataHashBuilder; + auxDataHashBuilder_governanceVotingRegistration_enter(auxDataHashBuilder, subctx->format); + auxDataHashBuilder_governanceVotingRegistration_enterPayload(auxDataHashBuilder); + } + + respondSuccessEmptyMsg(); + advanceState(); +} + +// ============================== VOTING KEY ============================== + +static void _parseVotingKey(read_view_t* view) +{ + governance_voting_registration_context_t* subctx = accessSubContext(); + + subctx->stateData.delegation.type = parse_u1be(view); + TRACE("delegation type = %d", (int) subctx->stateData.delegation.type); + switch (subctx->stateData.delegation.type) { + + case DELEGATION_KEY: { + STATIC_ASSERT( + SIZEOF(subctx->stateData.delegation.votingPubKey) == GOVERNANCE_VOTING_PUBLIC_KEY_LENGTH, + "wrong voting public key size" + ); + view_parseBuffer( + subctx->stateData.delegation.votingPubKey, + view, + GOVERNANCE_VOTING_PUBLIC_KEY_LENGTH + ); + break; + } + + case DELEGATION_PATH: { + view_skipBytes( + view, + bip44_parseFromWire( + &subctx->stateData.delegation.votingPubKeyPath, + VIEW_REMAINING_TO_TUPLE_BUF_SIZE(view) + ) + ); + TRACE(); + BIP44_PRINTF(&subctx->stateData.delegation.votingPubKeyPath); + PRINTF("\n"); + break; + } + + default: + THROW(ERR_INVALID_DATA); + } +} + +security_policy_t _determineVotingKeyPolicy() +{ + governance_voting_registration_context_t* subctx = accessSubContext(); + + switch (subctx->stateData.delegation.type) { + + case DELEGATION_PATH: + return policyForGovernanceVotingRegistrationVotingKeyPath( + &subctx->stateData.delegation.votingPubKeyPath, + subctx->format + ); + + case DELEGATION_KEY: + return policyForGovernanceVotingRegistrationVotingKey(); + + default: + ASSERT(false); + } + return POLICY_DENY; +} + +static void _displayVotingKey(ui_callback_fn_t callback) +{ + governance_voting_registration_context_t* subctx = accessSubContext(); + switch (subctx->stateData.delegation.type) { + case DELEGATION_KEY: { + STATIC_ASSERT(SIZEOF(subctx->stateData.delegation.votingPubKey) == GOVERNANCE_VOTING_PUBLIC_KEY_LENGTH, "wrong voting public key size"); + ui_displayBech32Screen( + "Voting public key", + "gov_vk", + subctx->stateData.delegation.votingPubKey, GOVERNANCE_VOTING_PUBLIC_KEY_LENGTH, + callback + ); + break; + } + case DELEGATION_PATH: { + ui_displayPathScreen( + "Voting public key", + &subctx->stateData.delegation.votingPubKeyPath, + callback + ); + break; + } + default: + ASSERT(false); + } +} + +enum { + HANDLE_VOTING_KEY_STEP_WARNING = 8200, + HANDLE_VOTING_KEY_STEP_DISPLAY, + HANDLE_VOTING_KEY_STEP_RESPOND, + HANDLE_VOTING_KEY_STEP_INVALID, +}; + +static void signTxGovernanceVotingRegistration_handleVotingKey_ui_runStep() +{ + governance_voting_registration_context_t* subctx = accessSubContext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = signTxGovernanceVotingRegistration_handleVotingKey_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_VOTING_KEY_STEP_WARNING) { + ui_displayPaginatedText( + "WARNING:", + "unusual voting key", + this_fn + ); + } + UI_STEP(HANDLE_VOTING_KEY_STEP_DISPLAY) { + _displayVotingKey(this_fn); + } + UI_STEP(HANDLE_VOTING_KEY_STEP_RESPOND) { + respondSuccessEmptyMsg(); + advanceState(); + } + UI_STEP_END(HANDLE_VOTING_KEY_STEP_INVALID); +} + +__noinline_due_to_stack__ +static void signTxGovernanceVotingRegistration_handleVotingKeyAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) +{ + { + CHECK_STATE(STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_KEY); + + ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); + } + governance_voting_registration_context_t* subctx = accessSubContext(); + { + explicit_bzero(&subctx->stateData, SIZEOF(subctx->stateData)); + } + { + TRACE_BUFFER(wireDataBuffer, wireDataSize); + read_view_t view = make_read_view(wireDataBuffer, wireDataBuffer + wireDataSize); + + _parseVotingKey(&view); + + VALIDATE(view_remainingSize(&view) == 0, ERR_INVALID_DATA); + } + + security_policy_t policy = _determineVotingKeyPolicy(); + TRACE("Policy: %d", (int) policy); + ENSURE_NOT_DENIED(policy); + + { + // add the key to hashbuilder + aux_data_hash_builder_t* auxDataHashBuilder = &AUX_DATA_CTX->auxDataHashBuilder; + + switch (subctx->stateData.delegation.type) { + + case DELEGATION_KEY: { + auxDataHashBuilder_governanceVotingRegistration_addVotingKey( + auxDataHashBuilder, subctx->stateData.delegation.votingPubKey, + GOVERNANCE_VOTING_PUBLIC_KEY_LENGTH + ); + break; + } + + case DELEGATION_PATH: { + extendedPublicKey_t extVotingPubKey; + deriveExtendedPublicKey(&subctx->stateData.delegation.votingPubKeyPath, &extVotingPubKey); + auxDataHashBuilder_governanceVotingRegistration_addVotingKey( + auxDataHashBuilder, extVotingPubKey.pubKey, SIZEOF(extVotingPubKey.pubKey) + ); + break; + } + + default: + ASSERT(false); + } + } + + { + // select UI steps + switch (policy) { +#define CASE(POLICY, UI_STEP) case POLICY: {subctx->ui_step=UI_STEP; break;} + CASE(POLICY_PROMPT_WARN_UNUSUAL, HANDLE_VOTING_KEY_STEP_WARNING); + CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_VOTING_KEY_STEP_DISPLAY); + CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_VOTING_KEY_STEP_RESPOND); +#undef CASE + default: + THROW(ERR_NOT_IMPLEMENTED); + } + } + + signTxGovernanceVotingRegistration_handleVotingKey_ui_runStep(); +} + +// ============================== DELEGATION ============================== + +enum { + HANDLE_DELEGATION_STEP_WARNING = 8300, + HANDLE_DELEGATION_STEP_VOTING_KEY, + HANDLE_DELEGATION_STEP_WEIGHT, + HANDLE_DELEGATION_STEP_RESPOND, + HANDLE_DELEGATION_STEP_INVALID, +}; + +static void signTxGovernanceVotingRegistration_handleDelegation_ui_runStep() +{ + governance_voting_registration_context_t* subctx = accessSubContext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = signTxGovernanceVotingRegistration_handleDelegation_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_VOTING_KEY_STEP_WARNING) { + ui_displayPaginatedText( + "WARNING:", + "unusual voting key", + this_fn + ); + } + UI_STEP(HANDLE_DELEGATION_STEP_VOTING_KEY) { + _displayVotingKey(this_fn); + } + UI_STEP(HANDLE_DELEGATION_STEP_WEIGHT) { + ui_displayUint64Screen( + "Weight", + subctx->stateData.delegation.weight, + this_fn + ); + } + UI_STEP(HANDLE_DELEGATION_STEP_RESPOND) { + respondSuccessEmptyMsg(); + subctx->currentDelegation++; + if (subctx->currentDelegation == subctx->numDelegations) { + advanceState(); + } + } + UI_STEP_END(HANDLE_DELEGATION_STEP_INVALID); +} + +__noinline_due_to_stack__ +static void signTxGovernanceVotingRegistration_handleDelegationAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) +{ + governance_voting_registration_context_t* subctx = accessSubContext(); + { + CHECK_STATE(STATE_GOVERNANCE_VOTING_REGISTRATION_DELEGATIONS); + ASSERT(subctx->currentDelegation < subctx->numDelegations); + } + { + explicit_bzero(&subctx->stateData, SIZEOF(subctx->stateData)); + } + { + TRACE_BUFFER(wireDataBuffer, wireDataSize); + read_view_t view = make_read_view(wireDataBuffer, wireDataBuffer + wireDataSize); + + _parseVotingKey(&view); + + subctx->stateData.delegation.weight = parse_u4be(&view); + TRACE("Governance voting registration delegation weight:"); + TRACE_UINT64(subctx->stateData.delegation.weight); + + VALIDATE(view_remainingSize(&view) == 0, ERR_INVALID_DATA); + } + + security_policy_t policy = _determineVotingKeyPolicy(); + TRACE("Policy: %d", (int) policy); + ENSURE_NOT_DENIED(policy); + + { + // add the key to hashbuilder + aux_data_hash_builder_t* auxDataHashBuilder = &AUX_DATA_CTX->auxDataHashBuilder; + + switch (subctx->stateData.delegation.type) { + + case DELEGATION_KEY: { + auxDataHashBuilder_governanceVotingRegistration_addDelegation( + auxDataHashBuilder, + subctx->stateData.delegation.votingPubKey, GOVERNANCE_VOTING_PUBLIC_KEY_LENGTH, + subctx->stateData.delegation.weight + ); + break; + } + + case DELEGATION_PATH: { + extendedPublicKey_t extVotingPubKey; + deriveExtendedPublicKey(&subctx->stateData.delegation.votingPubKeyPath, &extVotingPubKey); + auxDataHashBuilder_governanceVotingRegistration_addDelegation( + auxDataHashBuilder, + extVotingPubKey.pubKey, SIZEOF(extVotingPubKey.pubKey), + subctx->stateData.delegation.weight + ); + break; + } + + default: + ASSERT(false); + } + + } + { + // select UI steps + switch (policy) { +#define CASE(POLICY, UI_STEP) case POLICY: {subctx->ui_step=UI_STEP; break;} + CASE(POLICY_PROMPT_WARN_UNUSUAL, HANDLE_DELEGATION_STEP_WARNING); + CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_DELEGATION_STEP_VOTING_KEY); + CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_DELEGATION_STEP_RESPOND); +#undef CASE + default: + THROW(ERR_NOT_IMPLEMENTED); + } + } + + signTxGovernanceVotingRegistration_handleDelegation_ui_runStep(); +} + +// ============================== STAKING KEY ============================== + +enum { + HANDLE_STAKING_KEY_STEP_WARNING = 8400, + HANDLE_STAKING_KEY_STEP_DISPLAY, + HANDLE_STAKING_KEY_STEP_RESPOND, + HANDLE_STAKING_KEY_STEP_INVALID, +}; + +static void signTxGovernanceVotingRegistration_handleStakingKey_ui_runStep() +{ + governance_voting_registration_context_t* subctx = accessSubContext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = signTxGovernanceVotingRegistration_handleStakingKey_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_STAKING_KEY_STEP_WARNING) { + ui_displayPaginatedText( + "Unusual request", + "Proceed with care", + this_fn + ); + } + UI_STEP(HANDLE_STAKING_KEY_STEP_DISPLAY) { + ui_displayStakingKeyScreen( + &subctx->stakingKeyPath, + this_fn + ); + } + UI_STEP(HANDLE_STAKING_KEY_STEP_RESPOND) { + respondSuccessEmptyMsg(); + advanceState(); + } + UI_STEP_END(HANDLE_STAKING_KEY_STEP_INVALID); +} + +__noinline_due_to_stack__ +static void signTxGovernanceVotingRegistration_handleStakingKeyAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) +{ + TRACE_STACK_USAGE(); + { + // sanity checks + CHECK_STATE(STATE_GOVERNANCE_VOTING_REGISTRATION_STAKING_KEY); + ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); + } + governance_voting_registration_context_t* subctx = accessSubContext(); + { + explicit_bzero(&subctx->stakingKeyPath, SIZEOF(subctx->stakingKeyPath)); + } + { + // parse input + TRACE_BUFFER(wireDataBuffer, wireDataSize); + + read_view_t view = make_read_view(wireDataBuffer, wireDataBuffer + wireDataSize); + + view_skipBytes( + &view, + bip44_parseFromWire(&subctx->stakingKeyPath, VIEW_REMAINING_TO_TUPLE_BUF_SIZE(&view)) + ); + + VALIDATE(view_remainingSize(&view) == 0, ERR_INVALID_DATA); + + } + + security_policy_t policy = policyForGovernanceVotingRegistrationStakingKey( + &subctx->stakingKeyPath + ); + TRACE("Policy: %d", (int) policy); + ENSURE_NOT_DENIED(policy); + + { + extendedPublicKey_t extStakingPubKey; + deriveExtendedPublicKey(&subctx->stakingKeyPath, &extStakingPubKey); + auxDataHashBuilder_governanceVotingRegistration_addStakingKey( + &AUX_DATA_CTX->auxDataHashBuilder, extStakingPubKey.pubKey, SIZEOF(extStakingPubKey.pubKey) + ); + } + + { + // select UI step + switch (policy) { +#define CASE(POLICY, UI_STEP) case POLICY: {subctx->ui_step=UI_STEP; break;} + CASE(POLICY_PROMPT_WARN_UNUSUAL, HANDLE_STAKING_KEY_STEP_WARNING); + CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_STAKING_KEY_STEP_DISPLAY); + CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_STAKING_KEY_STEP_RESPOND); +#undef CASE + default: + THROW(ERR_NOT_IMPLEMENTED); + } + } + + signTxGovernanceVotingRegistration_handleStakingKey_ui_runStep(); +} + +// ============================== VOTING REWARDS ADDRESS ============================== + +static size_t _destinationToAddress( + tx_output_destination_storage_t* destination, + uint8_t* addressBuffer, + size_t addressBufferSize +) +{ + size_t addressSize = 0; + + switch (destination->type) { + case DESTINATION_DEVICE_OWNED: + addressSize = deriveAddress( + &destination->params, + addressBuffer, + addressBufferSize + ); + break; + + case DESTINATION_THIRD_PARTY: + addressSize = destination->address.size; + ASSERT(addressSize <= addressBufferSize); + memcpy( + addressBuffer, + destination->address.buffer, + addressSize + ); + break; + + default: + ASSERT(false); + } + + return addressSize; +} + +enum { + HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_WARNING = 8500, + HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS, + HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_RESPOND, + HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_INVALID +}; + +__noinline_due_to_stack__ +static void signTxGovernanceVotingRegistration_handleVotingRewardsAddress_ui_runStep() +{ + governance_voting_registration_context_t* subctx = accessSubContext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = signTxGovernanceVotingRegistration_handleVotingRewardsAddress_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_WARNING) { + ui_displayPaginatedText( + "Unusual request", + "Proceed with care", + this_fn + ); + } + UI_STEP(HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS) { + uint8_t addressBuffer[MAX_ADDRESS_SIZE] = {0}; + size_t addressSize = _destinationToAddress( + &subctx->stateData.rewardDestination, + addressBuffer, SIZEOF(addressBuffer) + ); + + ui_displayAddressScreen( + "Rewards go to", + addressBuffer, + addressSize, + this_fn + ); + } + UI_STEP(HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_RESPOND) { + respondSuccessEmptyMsg(); + advanceState(); + } + UI_STEP_END(HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_INVALID); +} + +__noinline_due_to_stack__ +static void signTxGovernanceVotingRegistration_handleVotingRewardsAddressAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) +{ + { + // safety checks + CHECK_STATE(STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_REWARDS_ADDRESS); + + ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); + } + governance_voting_registration_context_t* subctx = accessSubContext(); + { + explicit_bzero( + &subctx->stateData.rewardDestination, + SIZEOF(subctx->stateData.rewardDestination) + ); + } + { + TRACE_BUFFER(wireDataBuffer, wireDataSize); + + read_view_t view = make_read_view(wireDataBuffer, wireDataBuffer + wireDataSize); + + view_parseDestination(&view, &subctx->stateData.rewardDestination); + + VALIDATE(view_remainingSize(&view) == 0, ERR_INVALID_DATA); + } + + security_policy_t policy = policyForGovernanceVotingRegistrationVotingRewardsDestination( + &subctx->stateData.rewardDestination, + commonTxData->networkId + ); + TRACE("Policy: %d", (int) policy); + ENSURE_NOT_DENIED(policy); + + { + uint8_t addressBuffer[MAX_ADDRESS_SIZE] = {0}; + size_t addressSize = _destinationToAddress( + &subctx->stateData.rewardDestination, + addressBuffer, SIZEOF(addressBuffer) + ); + + auxDataHashBuilder_governanceVotingRegistration_addVotingRewardsAddress( + &AUX_DATA_CTX->auxDataHashBuilder, addressBuffer, addressSize + ); + } + + { + // select UI steps + switch (policy) { +#define CASE(POLICY, UI_STEP) case POLICY: {subctx->ui_step=UI_STEP; break;} + CASE(POLICY_PROMPT_WARN_UNUSUAL, HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_WARNING); + CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS); + CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_RESPOND); +#undef CASE + default: + THROW(ERR_NOT_IMPLEMENTED); + } + + signTxGovernanceVotingRegistration_handleVotingRewardsAddress_ui_runStep(); + } +} + +// ============================== NONCE ============================== + +enum { + HANDLE_NONCE_STEP_DISPLAY = 8600, + HANDLE_NONCE_STEP_RESPOND, + HANDLE_NONCE_STEP_INVALID, +}; + +static void signTxGovernanceVotingRegistration_handleNonce_ui_runStep() +{ + governance_voting_registration_context_t* subctx = accessSubContext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = signTxGovernanceVotingRegistration_handleNonce_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_NONCE_STEP_DISPLAY) { + ui_displayUint64Screen( + "Nonce", + subctx->stateData.nonce, + this_fn + ); + } + UI_STEP(HANDLE_NONCE_STEP_RESPOND) { + respondSuccessEmptyMsg(); + advanceState(); + } + UI_STEP_END(HANDLE_NONCE_STEP_INVALID); +} + +__noinline_due_to_stack__ +static void signTxGovernanceVotingRegistration_handleNonceAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) +{ + { + // sanity checks + CHECK_STATE(STATE_GOVERNANCE_VOTING_REGISTRATION_NONCE); + + ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); + } + governance_voting_registration_context_t* subctx = accessSubContext(); + { + explicit_bzero(&subctx->stateData, SIZEOF(subctx->stateData)); + } + { + // parse data + TRACE_BUFFER(wireDataBuffer, wireDataSize); + VALIDATE(wireDataSize == 8, ERR_INVALID_DATA); + subctx->stateData.nonce = u8be_read(wireDataBuffer); + TRACE("Governance voting registration nonce:"); + TRACE_UINT64(subctx->stateData.nonce); + } + + security_policy_t policy = policyForGovernanceVotingRegistrationNonce(); + TRACE("Policy: %d", (int) policy); + ENSURE_NOT_DENIED(policy); + + { + auxDataHashBuilder_governanceVotingRegistration_addNonce(&AUX_DATA_CTX->auxDataHashBuilder, subctx->stateData.nonce); + } + + { + // select UI steps + switch (policy) { +#define CASE(POLICY, UI_STEP) case POLICY: {subctx->ui_step=UI_STEP; break;} + CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_NONCE_STEP_DISPLAY); + CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_NONCE_STEP_RESPOND); +#undef CASE + default: + THROW(ERR_NOT_IMPLEMENTED); + } + } + + signTxGovernanceVotingRegistration_handleNonce_ui_runStep(); +} + +// ============================== VOTING PURPOSE ============================== + +enum { + HANDLE_VOTING_PURPOSE_STEP_DISPLAY = 8700, + HANDLE_VOTING_PURPOSE_STEP_RESPOND, + HANDLE_VOTING_PURPOSE_STEP_INVALID, +}; + +static void signTxGovernanceVotingRegistration_handleVotingPurpose_ui_runStep() +{ + governance_voting_registration_context_t* subctx = accessSubContext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = signTxGovernanceVotingRegistration_handleVotingPurpose_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_VOTING_PURPOSE_STEP_DISPLAY) { + ui_displayUint64Screen( + "Voting purpose", + subctx->stateData.votingPurpose, + this_fn + ); + } + UI_STEP(HANDLE_VOTING_PURPOSE_STEP_RESPOND) { + respondSuccessEmptyMsg(); + advanceState(); + } + UI_STEP_END(HANDLE_VOTING_PURPOSE_STEP_INVALID); +} + +#define DEFAULT_VOTING_PURPOSE (0) + +__noinline_due_to_stack__ +static void signTxGovernanceVotingRegistration_handleVotingPurposeAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) +{ + { + CHECK_STATE(STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_PURPOSE); + + ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); + } + governance_voting_registration_context_t* subctx = accessSubContext(); + { + explicit_bzero(&subctx->stateData, SIZEOF(subctx->stateData)); + } + { + TRACE_BUFFER(wireDataBuffer, wireDataSize); + + { + read_view_t view = make_read_view(wireDataBuffer, wireDataBuffer + wireDataSize); + + const uint8_t isIncluded = parse_u1be(&view); + bool isVotingPurposeIncluded = signTx_parseIncluded(isIncluded); + TRACE("isVotingPurposeIncluded = %u", isVotingPurposeIncluded); + if (isVotingPurposeIncluded) { + // only allowed in CIP36, not in CIP15 + VALIDATE(subctx->format == CIP36, ERR_INVALID_DATA); + } + + if (isVotingPurposeIncluded) { + subctx->stateData.votingPurpose = parse_u8be(&view); + } else { + subctx->stateData.votingPurpose = DEFAULT_VOTING_PURPOSE; + } + TRACE("votingPurpose = %u", subctx->stateData.votingPurpose); + + VALIDATE(view_remainingSize(&view) == 0, ERR_INVALID_DATA); + } + } + + if (subctx->format != CIP36) { + // nothing to do, the APDU was only received to simplify the state machine + respondSuccessEmptyMsg(); + advanceState(); + return; + } + + security_policy_t policy = policyForGovernanceVotingRegistrationVotingPurpose(); + TRACE("Policy: %d", (int) policy); + ENSURE_NOT_DENIED(policy); + + { + auxDataHashBuilder_governanceVotingRegistration_addVotingPurpose( + &AUX_DATA_CTX->auxDataHashBuilder, + subctx->stateData.votingPurpose + ); + } + { + // select UI steps + switch (policy) { +#define CASE(POLICY, UI_STEP) case POLICY: {subctx->ui_step=UI_STEP; break;} + CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_VOTING_PURPOSE_STEP_DISPLAY); + CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_VOTING_PURPOSE_STEP_RESPOND); +#undef CASE + default: + THROW(ERR_NOT_IMPLEMENTED); + } + } + + signTxGovernanceVotingRegistration_handleVotingPurpose_ui_runStep(); +} + + +// ============================== CONFIRM ============================== + +enum { + HANDLE_CONFIRM_STEP_FINAL_CONFIRM = 8800, + HANDLE_CONFIRM_STEP_DISPLAY_HASH, + HANDLE_CONFIRM_STEP_RESPOND, + HANDLE_CONFIRM_STEP_INVALID, +}; + +static void signTxGovernanceVotingRegistration_handleConfirm_ui_runStep() +{ + governance_voting_registration_context_t* subctx = accessSubContext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = signTxGovernanceVotingRegistration_handleConfirm_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + UI_STEP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM) { + // confirming this means the signature being sent out of the device + // so we want to show it in non-expert mode too + ui_displayPrompt( + "Confirm voting key", + "registration?", + this_fn, + respond_with_user_reject + ); + } + UI_STEP(HANDLE_CONFIRM_STEP_DISPLAY_HASH) { + if (!app_mode_expert()) { + UI_STEP_JUMP(HANDLE_CONFIRM_STEP_RESPOND); + } + ui_displayHexBufferScreen( + "Auxiliary data hash", + subctx->auxDataHash, + SIZEOF(subctx->auxDataHash), + this_fn + ); + } + UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { + struct { + uint8_t auxDataHash[AUX_DATA_HASH_LENGTH]; + uint8_t signature[ED25519_SIGNATURE_LENGTH]; + } wireResponse = {0}; + + STATIC_ASSERT(SIZEOF(subctx->auxDataHash) == AUX_DATA_HASH_LENGTH, "Wrong aux data hash length"); + memmove(wireResponse.auxDataHash, subctx->auxDataHash, AUX_DATA_HASH_LENGTH); + + STATIC_ASSERT(SIZEOF(subctx->stateData.registrationSignature) == ED25519_SIGNATURE_LENGTH, "Wrong governance voting registration signature length"); + memmove(wireResponse.signature, subctx->stateData.registrationSignature, ED25519_SIGNATURE_LENGTH); + + io_send_buf(SUCCESS, (uint8_t*) &wireResponse, SIZEOF(wireResponse)); + advanceState(); + } + UI_STEP_END(HANDLE_CONFIRM_STEP_INVALID); +} + +__noinline_due_to_stack__ +static void signTxGovernanceVotingRegistration_handleConfirmAPDU(const uint8_t* wireDataBuffer MARK_UNUSED, size_t wireDataSize) +{ + { + //sanity checks + CHECK_STATE(STATE_GOVERNANCE_VOTING_REGISTRATION_CONFIRM); + + ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); + } + governance_voting_registration_context_t* subctx = accessSubContext(); + { + explicit_bzero(&subctx->stateData, SIZEOF(subctx->stateData)); + } + + { + // no data to receive + VALIDATE(wireDataSize == 0, ERR_INVALID_DATA); + } + + security_policy_t policy = policyForGovernanceVotingRegistrationConfirm(); + TRACE("Policy: %d", (int) policy); + ENSURE_NOT_DENIED(policy); + + { + aux_data_hash_builder_t* auxDataHashBuilder = &AUX_DATA_CTX->auxDataHashBuilder; + { + uint8_t votingPayloadHashBuffer[GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_HASH_LENGTH] = {0}; + auxDataHashBuilder_governanceVotingRegistration_finalizePayload(auxDataHashBuilder, votingPayloadHashBuffer, AUX_DATA_HASH_LENGTH); + getGovernanceVotingRegistrationSignature( + &subctx->stakingKeyPath, + votingPayloadHashBuffer, GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_HASH_LENGTH, + subctx->stateData.registrationSignature, ED25519_SIGNATURE_LENGTH + ); + } + auxDataHashBuilder_governanceVotingRegistration_addSignature(auxDataHashBuilder, subctx->stateData.registrationSignature, ED25519_SIGNATURE_LENGTH); + auxDataHashBuilder_governanceVotingRegistration_addAuxiliaryScripts(auxDataHashBuilder); + + auxDataHashBuilder_finalize(auxDataHashBuilder, subctx->auxDataHash, AUX_DATA_HASH_LENGTH); + } + + { + // select UI steps + switch (policy) { +#define CASE(POLICY, UI_STEP) case POLICY: {subctx->ui_step=UI_STEP; break;} + CASE(POLICY_PROMPT_BEFORE_RESPONSE, HANDLE_CONFIRM_STEP_FINAL_CONFIRM); + CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_CONFIRM_STEP_RESPOND); +#undef CASE + default: + THROW(ERR_NOT_IMPLEMENTED); + } + } + + signTxGovernanceVotingRegistration_handleConfirm_ui_runStep(); +} + + +// ============================== main APDU handler ============================== + +enum { + APDU_INSTRUCTION_INIT = 0x36, + APDU_INSTRUCTION_VOTING_KEY = 0x30, + APDU_INSTRUCTION_DELEGATION = 0x37, + APDU_INSTRUCTION_STAKING_KEY = 0x31, + APDU_INSTRUCTION_VOTING_REWARDS_ADDRESS = 0x32, + APDU_INSTRUCTION_NONCE = 0x33, + APDU_INSTRUCTION_VOTING_PURPOSE = 0x35, + APDU_INSTRUCTION_CONFIRM = 0x34 +}; + +bool signTxGovernanceVotingRegistration_isValidInstruction(uint8_t p2) +{ + switch (p2) { + case APDU_INSTRUCTION_INIT: + case APDU_INSTRUCTION_VOTING_KEY: + case APDU_INSTRUCTION_DELEGATION: + case APDU_INSTRUCTION_STAKING_KEY: + case APDU_INSTRUCTION_VOTING_REWARDS_ADDRESS: + case APDU_INSTRUCTION_NONCE: + case APDU_INSTRUCTION_VOTING_PURPOSE: + case APDU_INSTRUCTION_CONFIRM: + return true; + + default: + return false; + } +} + +void signTxGovernanceVotingRegistration_handleAPDU(uint8_t p2, const uint8_t* wireDataBuffer, size_t wireDataSize) +{ + ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); + + switch (p2) { + case APDU_INSTRUCTION_INIT: + signTxGovernanceVotingRegistration_handleInitAPDU(wireDataBuffer, wireDataSize); + break; + + case APDU_INSTRUCTION_VOTING_KEY: + signTxGovernanceVotingRegistration_handleVotingKeyAPDU(wireDataBuffer, wireDataSize); + break; + + case APDU_INSTRUCTION_DELEGATION: + signTxGovernanceVotingRegistration_handleDelegationAPDU(wireDataBuffer, wireDataSize); + break; + + case APDU_INSTRUCTION_STAKING_KEY: + signTxGovernanceVotingRegistration_handleStakingKeyAPDU(wireDataBuffer, wireDataSize); + break; + + case APDU_INSTRUCTION_VOTING_REWARDS_ADDRESS: + signTxGovernanceVotingRegistration_handleVotingRewardsAddressAPDU(wireDataBuffer, wireDataSize); + break; + + case APDU_INSTRUCTION_NONCE: + signTxGovernanceVotingRegistration_handleNonceAPDU(wireDataBuffer, wireDataSize); + break; + + case APDU_INSTRUCTION_VOTING_PURPOSE: + signTxGovernanceVotingRegistration_handleVotingPurposeAPDU(wireDataBuffer, wireDataSize); + break; + + case APDU_INSTRUCTION_CONFIRM: + signTxGovernanceVotingRegistration_handleConfirmAPDU(wireDataBuffer, wireDataSize); + break; + + default: + // this is not supposed to be called with invalid p2 + ASSERT(false); + } +} diff --git a/src/signTxGovernanceVotingRegistration.h b/src/signTxGovernanceVotingRegistration.h new file mode 100644 index 00000000..933a176f --- /dev/null +++ b/src/signTxGovernanceVotingRegistration.h @@ -0,0 +1,70 @@ +#ifndef H_CARDANO_APP_SIGN_TX_GOVERNANCE_VOTING_REGISTRATION +#define H_CARDANO_APP_SIGN_TX_GOVERNANCE_VOTING_REGISTRATION + +#include "common.h" +#include "cardano.h" +#include "auxDataHashBuilder.h" +#include "txHashBuilder.h" +#include "addressUtilsShelley.h" + + +#define GOVERNANCE_VOTING_PUBLIC_KEY_LENGTH 32 + +// SIGN_STAGE_AUX_DATA = 24 +// AUX_DATA_TYPE_GOVERNANCE_VOTING_REGISTRATION = 1 +typedef enum { + STATE_GOVERNANCE_VOTING_REGISTRATION_INIT = 2410, + STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_KEY = 2411, + STATE_GOVERNANCE_VOTING_REGISTRATION_DELEGATIONS = 2412, + STATE_GOVERNANCE_VOTING_REGISTRATION_STAKING_KEY = 2413, + STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_REWARDS_ADDRESS = 2414, + STATE_GOVERNANCE_VOTING_REGISTRATION_NONCE = 2415, + STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_PURPOSE = 2416, + STATE_GOVERNANCE_VOTING_REGISTRATION_CONFIRM = 2417, + STATE_GOVERNANCE_VOTING_REGISTRATION_FINISHED = 2418 +} sign_tx_governance_voting_registration_state_t; + +typedef enum { + DELEGATION_KEY = 1, + DELEGATION_PATH = 2 +} governance_voting_delegation_type_t; + +typedef struct { + sign_tx_governance_voting_registration_state_t state; + int ui_step; + + governance_voting_registration_format_t format; + uint16_t numDelegations; // if 0, only a single key expected, no delegations + uint16_t currentDelegation; + /* + * Staking key path kept outside of stateData to produce the governance voting registration + * signature at the end of the flow without re-requesting the staking key path + * (with the undesired side-effect of allowing signing with a different key than included + * in the registration payload) + */ + bip44_path_t stakingKeyPath; + + uint8_t auxDataHash[AUX_DATA_HASH_LENGTH]; + + union { + struct { + governance_voting_delegation_type_t type; + bip44_path_t votingPubKeyPath; + uint8_t votingPubKey[GOVERNANCE_VOTING_PUBLIC_KEY_LENGTH]; + uint32_t weight; + } delegation; + tx_output_destination_storage_t rewardDestination; + uint64_t nonce; + uint64_t votingPurpose; + uint8_t registrationSignature[ED25519_SIGNATURE_LENGTH]; + } stateData; +} governance_voting_registration_context_t; + +void signTxGovernanceVotingRegistration_init(); + +bool signTxGovernanceVotingRegistration_isValidInstruction(uint8_t p2); +void signTxGovernanceVotingRegistration_handleAPDU(uint8_t p2, const uint8_t* wireDataBuffer, size_t wireDataSize); + +bool signTxGovernanceVotingRegistration_isFinished(); + +#endif // H_CARDANO_APP_SIGN_TX_GOVERNANCE_VOTING_REGISTRATION diff --git a/src/signTxOutput.c b/src/signTxOutput.c index 64bde039..6f09ae2c 100644 --- a/src/signTxOutput.c +++ b/src/signTxOutput.c @@ -427,18 +427,6 @@ static bool _isValidOutputSerializationFormat(tx_output_serialization_format_t f } } -static bool _isValidDestinationType(tx_output_destination_type_t type) -{ - switch (type) { - case DESTINATION_THIRD_PARTY: - case DESTINATION_DEVICE_OWNED: - return true; - - default: - return false; - } -} - static void parseTopLevelData(const uint8_t* wireDataBuffer, size_t wireDataSize) { { @@ -457,32 +445,9 @@ static void parseTopLevelData(const uint8_t* wireDataBuffer, size_t wireDataSize subctx->serializationFormat = parse_u1be(&view); TRACE("Output serialization format %d", (int) subctx->serializationFormat); - _isValidOutputSerializationFormat(subctx->serializationFormat); - - subctx->stateData.destination.type = parse_u1be(&view); - TRACE("Output destination type %d", (int) subctx->stateData.destination.type); - _isValidDestinationType(subctx->stateData.destination.type); - - switch (subctx->stateData.destination.type) { - case DESTINATION_THIRD_PARTY: { - STATIC_ASSERT(sizeof(subctx->stateData.destination.address.size) >= 4, "wrong address size type"); - subctx->stateData.destination.address.size = parse_u4be(&view); - TRACE("Address length %u", subctx->stateData.destination.address.size); - VALIDATE(subctx->stateData.destination.address.size <= MAX_ADDRESS_SIZE, ERR_INVALID_DATA); - - STATIC_ASSERT(SIZEOF(subctx->stateData.destination.address.buffer) >= MAX_ADDRESS_SIZE, "wrong address buffer size"); - view_parseBuffer(subctx->stateData.destination.address.buffer, &view, subctx->stateData.destination.address.size); - TRACE_BUFFER(subctx->stateData.destination.address.buffer, subctx->stateData.destination.address.size); - break; - } - case DESTINATION_DEVICE_OWNED: { - view_parseAddressParams(&view, &subctx->stateData.destination.params); - break; - } + VALIDATE(_isValidOutputSerializationFormat(subctx->serializationFormat), ERR_INVALID_DATA); - default: - THROW(ERR_INVALID_DATA); - }; + view_parseDestination(&view, &subctx->stateData.destination); uint64_t adaAmount = parse_u8be(&view); subctx->stateData.adaAmount = adaAmount; diff --git a/src/signTxUtils.c b/src/signTxUtils.c index c2ac296f..f879be47 100644 --- a/src/signTxUtils.c +++ b/src/signTxUtils.c @@ -10,7 +10,7 @@ void respondSuccessEmptyMsg() { TRACE(); io_send_buf(SUCCESS, NULL, 0); - ui_displayBusy(); // displays dots, called after I/O to avoid freezing + ui_displayBusy(); // displays dots, called only after I/O to avoid freezing } bool violatesSingleAccountOrStoreIt(const bip44_path_t* path) @@ -34,7 +34,7 @@ bool violatesSingleAccountOrStoreIt(const bip44_path_t* path) return true; } const bool combinesByronAndShelley = singleAccountData->isByron != isByron; - const bool combinationAllowed = (storedAccount == 0 + HARDENED_BIP32); + const bool combinationAllowed = (storedAccount == harden(0)); if (combinesByronAndShelley && !combinationAllowed) { return true; } @@ -45,3 +45,31 @@ bool violatesSingleAccountOrStoreIt(const bip44_path_t* path) } return false; } + +void view_parseDestination(read_view_t* view, tx_output_destination_storage_t* destination) { + destination->type = parse_u1be(view); + TRACE("Destination type %d", (int) destination->type); + + switch (destination->type) { // serves as validation of the type too + + case DESTINATION_THIRD_PARTY: { + STATIC_ASSERT(sizeof(destination->address.size) >= 4, "wrong address size type"); + destination->address.size = parse_u4be(view); + TRACE("Address length %u", destination->address.size); + VALIDATE(destination->address.size <= MAX_ADDRESS_SIZE, ERR_INVALID_DATA); + + STATIC_ASSERT(SIZEOF(destination->address.buffer) >= MAX_ADDRESS_SIZE, "wrong address buffer size"); + view_parseBuffer(destination->address.buffer, view, destination->address.size); + TRACE_BUFFER(destination->address.buffer, destination->address.size); + break; + } + + case DESTINATION_DEVICE_OWNED: { + view_parseAddressParams(view, &destination->params); + break; + } + + default: + THROW(ERR_INVALID_DATA); + }; +} diff --git a/src/signTxUtils.h b/src/signTxUtils.h index 6520f5ed..8f5baf3f 100644 --- a/src/signTxUtils.h +++ b/src/signTxUtils.h @@ -2,6 +2,7 @@ #define H_CARDANO_APP_SIGN_TX_UTILS #include "bip44.h" +#include "txHashBuilder.h" void respondSuccessEmptyMsg(); @@ -15,4 +16,6 @@ void respondSuccessEmptyMsg(); */ bool violatesSingleAccountOrStoreIt(const bip44_path_t* path); +void view_parseDestination(read_view_t* view, tx_output_destination_storage_t* destination); + #endif // H_CARDANO_APP_SIGN_TX_UTILS diff --git a/src/state.h b/src/state.h index 8549086b..1d71bb90 100644 --- a/src/state.h +++ b/src/state.h @@ -7,6 +7,7 @@ #include "deriveNativeScriptHash.h" #include "signTx.h" #include "signOpCert.h" +#include "signGovernanceVote.h" typedef union { @@ -16,6 +17,7 @@ typedef union { ins_derive_native_script_hash_context_t deriveNativeScriptHashContext; ins_sign_tx_context_t signTxContext; ins_sign_op_cert_context_t signOpCertContext; + ins_sign_governance_vote_context_t signGovernanceVoteContext; } instructionState_t; // Note(instructions are uint8_t but we have a special INS_NONE value diff --git a/src/txHashBuilder.c b/src/txHashBuilder.c index b20cd99b..0dc11251 100644 --- a/src/txHashBuilder.c +++ b/src/txHashBuilder.c @@ -32,8 +32,7 @@ The following macros and functions have dual purpose: static void blake2b_256_append_buffer_tx_body( blake2b_256_context_t* hashCtx, - const uint8_t* buffer, - size_t bufferSize + const uint8_t* buffer, size_t bufferSize ) { TRACE_BUFFER(buffer, bufferSize); diff --git a/src/uiScreens.c b/src/uiScreens.c index d304c3f8..d2e53066 100644 --- a/src/uiScreens.c +++ b/src/uiScreens.c @@ -186,7 +186,7 @@ void ui_displayStakingKeyScreen( { ASSERT(bip44_isOrdinaryStakingKeyPath(stakingPath)); - bool showAccountDescription = bip44_hasReasonableAccount(stakingPath); + bool showAccountDescription = bip44_isPathReasonable(stakingPath); _ui_displayAccountWithDescriptionScreen( "Staking key", diff --git a/src/utils.h b/src/utils.h index e0634ec5..a8be7df5 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,8 +1,9 @@ #ifndef H_CARDANO_APP_UTILS #define H_CARDANO_APP_UTILS -#include "assert.h" +#include +#include "assert.h" // Does not compile if x is pointer of some kind // See http://zubplot.blogspot.com/2015/01/gcc-is-wonderful-better-arraysize-macro.html diff --git a/src/votecastHashBuilder.c b/src/votecastHashBuilder.c new file mode 100644 index 00000000..1e94fc19 --- /dev/null +++ b/src/votecastHashBuilder.c @@ -0,0 +1,99 @@ +#include "common.h" +#include "votecastHashBuilder.h" +#include "hash.h" +#include "bufView.h" + +// this tracing is rarely needed +// so we want to keep it turned off to avoid polluting the trace log + +//#define TRACE_VOTECAST_HASH_BUILDER + +#ifdef TRACE_VOTECAST_HASH_BUILDER +#define _TRACE(...) TRACE(__VA_ARGS__) +#else +#define _TRACE(...) +#endif // TRACE_VOTECAST_HASH_BUILDER + + +/* +The following macros and functions have dual purpose: +1. syntactic sugar for neat recording of hash computations; +2. tracing of hash computations (allows to reconstruct bytestrings we are hashing via speculos / usbtool). +*/ + +#define BUILDER_APPEND_DATA(buffer, bufferSize) \ + blake2b_256_append_buffer_tx_body(&builder->hash, buffer, bufferSize) + + +static void blake2b_256_append_buffer_tx_body( + blake2b_256_context_t* hashCtx, + const uint8_t* buffer, + size_t bufferSize +) +{ + TRACE_BUFFER(buffer, bufferSize); + blake2b_256_append(hashCtx, buffer, bufferSize); +} + +/* End of hash computation utilities. */ + +// ============================== TX HASH BUILDER STATE INITIALIZATION ============================== + +void votecastHashBuilder_init( + votecast_hash_builder_t* builder, + size_t remainingBytes +) +{ + TRACE("remainingBytes = %u", remainingBytes); + + ASSERT(remainingBytes > 0); + builder->remainingBytes = remainingBytes; + + blake2b_256_init(&builder->hash); + + builder->state = VOTECAST_HASH_BUILDER_INIT; +} + +// ============================== CHUNK ============================== + +void votecastHashBuilder_chunk( + votecast_hash_builder_t* builder, + const uint8_t* chunk, size_t chunkSize +) +{ + _TRACE("state = %d", builder->state); + + ASSERT( + builder->state == VOTECAST_HASH_BUILDER_INIT || + builder->state == VOTECAST_HASH_BUILDER_CHUNK + ); + + ASSERT(chunkSize < BUFFER_SIZE_PARANOIA); + ASSERT(chunkSize <= builder->remainingBytes); + ASSERT(chunkSize > 0); + builder->remainingBytes -= chunkSize; + + BUILDER_APPEND_DATA(chunk, chunkSize); + + builder->state = VOTECAST_HASH_BUILDER_CHUNK; +} + +// ========================= FINALIZE ========================== + +void votecastHashBuilder_finalize( + votecast_hash_builder_t* builder, + uint8_t* outBuffer, size_t outSize +) +{ + _TRACE("state = %d", builder->state); + + ASSERT(builder->state == VOTECAST_HASH_BUILDER_CHUNK); + ASSERT(builder->remainingBytes == 0); + + ASSERT(outSize == VOTECAST_HASH_LENGTH); + { + blake2b_256_finalize(&builder->hash, outBuffer, outSize); + } + + builder->state = VOTECAST_HASH_BUILDER_FINISHED; +} diff --git a/src/votecastHashBuilder.h b/src/votecastHashBuilder.h new file mode 100644 index 00000000..793dbd73 --- /dev/null +++ b/src/votecastHashBuilder.h @@ -0,0 +1,37 @@ +#ifndef H_CARDANO_APP_VOTECAST_HASH_BUILDER +#define H_CARDANO_APP_VOTECAST_HASH_BUILDER + +#include "hash.h" + +#define VOTECAST_HASH_LENGTH 32 + +typedef enum { + VOTECAST_HASH_BUILDER_INIT = 100, + VOTECAST_HASH_BUILDER_CHUNK = 200, + VOTECAST_HASH_BUILDER_FINISHED = 1800, +} votecast_hash_builder_state_t; + +typedef struct { + votecast_hash_builder_state_t state; + + size_t remainingBytes; + + blake2b_256_context_t hash; +} votecast_hash_builder_t; + +void votecastHashBuilder_init( + votecast_hash_builder_t* builder, + size_t remainingBytes +); + +void votecastHashBuilder_chunk( + votecast_hash_builder_t* builder, + const uint8_t* chunk, size_t chunkSize +); + +void votecastHashBuilder_finalize( + votecast_hash_builder_t* builder, + uint8_t* outBuffer, size_t outSize +); + +#endif // H_CARDANO_APP_VOTECAST_HASH_BUILDER From 786243fe4acbdf55b452b251f981b4f9901983a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1n=20Maz=C3=A1k?= <42575685+janmazak@users.noreply.github.com> Date: Wed, 14 Dec 2022 16:47:51 +0100 Subject: [PATCH 002/105] Update native token list (#31) * fix: validation of P2 values * update list of tokens * update version to 6.0.1 --- CHANGELOG.md | 3 +- Makefile | 2 +- src/signTx.c | 15 +- tokenRegistry/convert.py | 2 +- tokenRegistry/token_data.c | 14 +- ...ist_ep321-337.json => top100JsonList.json} | 560 ++++-------------- 6 files changed, 149 insertions(+), 447 deletions(-) rename tokenRegistry/{top100JsonList_ep321-337.json => top100JsonList.json} (59%) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd00d680..356cdf6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [6.0.0](TBD) - [TBD] +## [6.0.1](TBD) - [TBD] Support for governance voting (CIP-0036) @@ -19,6 +19,7 @@ Support for governance voting (CIP-0036) ### Changed - API for Catalyst voting registration (it is still possible to use CIP-0015 in auxiliary data) +- updated list of native tokens recognized by the app with correct decimal places ## [5.0.0](https://github.com/LedgerHQ/app-cardano/compare/4.1.2...LedgerHQ:nanos_2.1.0_5.0.0) - [October 11th 2022] diff --git a/Makefile b/Makefile index ed327d43..f5ca3bb1 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ APPNAME = "Cardano ADA" APPVERSION_M = 6 APPVERSION_N = 0 -APPVERSION_P = 0 +APPVERSION_P = 1 APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" ifeq ($(BOLOS_SDK),) diff --git a/src/signTx.c b/src/signTx.c index 55b9ab65..350bba6b 100644 --- a/src/signTx.c +++ b/src/signTx.c @@ -763,7 +763,7 @@ static void signTx_handleAuxDataAPDU(uint8_t p2, const uint8_t* wireDataBuffer, ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); ASSERT(ctx->includeAuxData == true); - // delegate to state sub-machine for stake pool registration certificate data + // delegate to state sub-machine for governance voting registration data if (signTxGovernanceVotingRegistration_isValidInstruction(p2)) { TRACE(); CHECK_STAGE(SIGN_STAGE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_SUBMACHINE); @@ -772,9 +772,10 @@ static void signTx_handleAuxDataAPDU(uint8_t p2, const uint8_t* wireDataBuffer, signTxGovernanceVotingRegistration_handleAPDU(p2, wireDataBuffer, wireDataSize); return; - } else { - CHECK_STAGE(SIGN_STAGE_AUX_DATA); } + + VALIDATE(p2 == P2_UNUSED, ERR_INVALID_REQUEST_PARAMETERS); + CHECK_STAGE(SIGN_STAGE_AUX_DATA); } { explicit_bzero(ctx->auxDataHash, SIZEOF(ctx->auxDataHash)); @@ -978,7 +979,7 @@ static void signTx_handleOutputAPDU(uint8_t p2, const uint8_t* wireDataBuffer, s ASSERT(BODY_CTX->currentOutput < ctx->numOutputs); // all output handling is delegated to a state sub-machine - VALIDATE(signTxOutput_isValidInstruction(p2), ERR_INVALID_DATA); + VALIDATE(signTxOutput_isValidInstruction(p2), ERR_INVALID_REQUEST_PARAMETERS); signTxOutput_handleAPDU(p2, wireDataBuffer, wireDataSize); } @@ -1478,8 +1479,8 @@ static void signTx_handleCertificateAPDU(uint8_t p2, const uint8_t* wireDataBuff return; } - CHECK_STAGE(SIGN_STAGE_BODY_CERTIFICATES); VALIDATE(p2 == P2_UNUSED, ERR_INVALID_REQUEST_PARAMETERS); + CHECK_STAGE(SIGN_STAGE_BODY_CERTIFICATES); // a new certificate arrived explicit_bzero(&BODY_CTX->stageData.certificate, SIZEOF(BODY_CTX->stageData.certificate)); @@ -1847,7 +1848,7 @@ static void signTx_handleMintAPDU(uint8_t p2, const uint8_t* wireDataBuffer, siz CHECK_STAGE(SIGN_STAGE_BODY_MINT_SUBMACHINE); // all mint handling is delegated to a state sub-machine - VALIDATE(signTxMint_isValidInstruction(p2), ERR_INVALID_DATA); + VALIDATE(signTxMint_isValidInstruction(p2), ERR_INVALID_REQUEST_PARAMETERS); signTxMint_handleAPDU(p2, wireDataBuffer, wireDataSize); } @@ -2118,7 +2119,7 @@ static void signTx_handleCollateralOutputAPDU(uint8_t p2, const uint8_t* wireDat CHECK_STAGE(SIGN_STAGE_BODY_COLLATERAL_OUTPUT_SUBMACHINE); // all output handling is delegated to a state sub-machine - VALIDATE(signTxCollateralOutput_isValidInstruction(p2), ERR_INVALID_DATA); + VALIDATE(signTxCollateralOutput_isValidInstruction(p2), ERR_INVALID_REQUEST_PARAMETERS); signTxCollateralOutput_handleAPDU(p2, wireDataBuffer, wireDataSize); } diff --git a/tokenRegistry/convert.py b/tokenRegistry/convert.py index 588cd765..8dc64a56 100644 --- a/tokenRegistry/convert.py +++ b/tokenRegistry/convert.py @@ -6,7 +6,7 @@ # WARNING --- make sure that: # 1. token tickers are meaningful and none is "(unknown decimals)" # 2. buffers (e.g. tokenAmountStr) are big enough to hold the tickers -filename = "top100JsonList_ep321-337.json" +filename = "top100JsonList.json" registry = json.load(open(filename)) diff --git a/tokenRegistry/token_data.c b/tokenRegistry/token_data.c index e71723e6..2e4b6f95 100644 --- a/tokenRegistry/token_data.c +++ b/tokenRegistry/token_data.c @@ -41,7 +41,6 @@ { { 0x55, 0xdf, 0x7e, 0x8b, 0x8f, 0x95, 0x5a, 0xc6, 0x5a, 0xba, 0x1d, 0xc9, 0x84, 0xa3, 0xc2, 0xf9, 0x56, 0x57, 0xbe, 0x7f }, 6, "MINt" }, { { 0x0b, 0xae, 0x47, 0x5b, 0xc6, 0xa5, 0x51, 0xe8, 0x94, 0x51, 0x68, 0x20, 0xaa, 0xd0, 0x1a, 0x51, 0x39, 0x5f, 0x32, 0x57 }, 0, "MILK" }, { { 0xc1, 0x40, 0xcd, 0xae, 0x75, 0xd4, 0xe3, 0x27, 0x28, 0x3e, 0xda, 0x2b, 0x1e, 0x81, 0xb6, 0xbc, 0x6e, 0x64, 0xdc, 0x2a }, 6, "ETB" }, -{ { 0xc3, 0x92, 0x7c, 0x48, 0x4c, 0xdc, 0x24, 0x46, 0xfe, 0x1d, 0x71, 0xa3, 0xf4, 0x72, 0x5b, 0x1b, 0x9b, 0xf5, 0x70, 0x47 }, 6, "DANA" }, { { 0xc1, 0xb9, 0x94, 0x86, 0xca, 0xf1, 0x1a, 0xd8, 0x93, 0xb9, 0xcc, 0x59, 0x27, 0x0d, 0x22, 0x00, 0x71, 0xce, 0xd5, 0xeb }, 0, "SWEET" }, { { 0x0a, 0xe3, 0xb4, 0x86, 0xe8, 0x5a, 0xf1, 0x50, 0xb4, 0x78, 0x1a, 0x13, 0x17, 0x1f, 0x27, 0x91, 0x4b, 0x3c, 0xb6, 0x1b }, 0, "TOKEN" }, { { 0xbc, 0xca, 0x70, 0x17, 0x1f, 0xa6, 0x6f, 0x68, 0x0a, 0xe9, 0x3d, 0x42, 0x3b, 0xac, 0xac, 0x97, 0xcd, 0xa6, 0xd7, 0x91 }, 6, "RAT" }, @@ -51,15 +50,12 @@ { { 0x33, 0xc2, 0xc5, 0x94, 0xcc, 0xf0, 0x2b, 0xeb, 0x0d, 0x45, 0xa8, 0xa2, 0xcc, 0x7e, 0x44, 0xa8, 0x15, 0x16, 0xe4, 0x66 }, 0, "Pina" }, { { 0x87, 0xfa, 0x98, 0x6b, 0xf9, 0x96, 0x47, 0x9a, 0xa1, 0xc1, 0x5c, 0x58, 0xc3, 0x72, 0xfc, 0x17, 0xeb, 0x27, 0x09, 0xdf }, 5, "MKA" }, { { 0x14, 0xff, 0x3e, 0x56, 0x0a, 0xe3, 0x23, 0x91, 0xcd, 0x49, 0xa2, 0xb1, 0x01, 0x6a, 0x1a, 0x0b, 0x07, 0x41, 0xa7, 0x4d }, 6, "VYFI" }, -{ { 0xa9, 0x1e, 0xd3, 0x40, 0x45, 0x81, 0x66, 0xd5, 0x7f, 0x29, 0xb0, 0x19, 0xce, 0x7b, 0x2d, 0x07, 0xe0, 0x8a, 0x07, 0xcf }, 0, "XRAY" }, { { 0x38, 0x1e, 0xf2, 0xfb, 0x1d, 0x8d, 0xd7, 0x8e, 0x90, 0x78, 0x32, 0xca, 0x76, 0x3e, 0x47, 0x30, 0xe8, 0x46, 0xd7, 0xfd }, 0, "virus" }, -{ { 0x88, 0x19, 0xed, 0x0f, 0x94, 0x5a, 0xfc, 0x5f, 0xb2, 0xae, 0xfc, 0x20, 0x46, 0xb6, 0xc5, 0x77, 0xb6, 0xb3, 0x38, 0x14 }, 0, "FLICK" }, { { 0x7d, 0x4b, 0xf1, 0x92, 0xd8, 0xfa, 0xf3, 0x67, 0xa8, 0xa2, 0x7d, 0xd2, 0x31, 0x4f, 0xca, 0x7d, 0xd8, 0x13, 0xc9, 0x5b }, 6, "PROXIE" }, { { 0x0e, 0x33, 0xb8, 0xea, 0x4b, 0x9f, 0x7a, 0x3c, 0x9f, 0x81, 0x72, 0x1b, 0xbf, 0x7c, 0xfb, 0xa2, 0x5f, 0x51, 0x9e, 0x27 }, 0, "CHRLZ" }, { { 0xea, 0x75, 0xb6, 0xf2, 0x1f, 0x34, 0x2f, 0x99, 0x4d, 0xe7, 0x88, 0xc0, 0x51, 0xd4, 0x52, 0xa0, 0x4e, 0xaa, 0x59, 0x6c }, 0, "RAD" }, { { 0x24, 0x5b, 0x57, 0x63, 0xc4, 0x1e, 0x81, 0x9e, 0x55, 0xaa, 0xe4, 0x50, 0x79, 0x41, 0xe8, 0x11, 0x35, 0x3b, 0xdf, 0xee }, 3, "CLAP" }, { { 0xd8, 0x79, 0xde, 0xfe, 0x51, 0xc6, 0x31, 0xe6, 0x27, 0x38, 0x82, 0x03, 0xe2, 0xe9, 0x6a, 0x6c, 0xf4, 0xa0, 0x2f, 0x18 }, 6, "GTCHI" }, -{ { 0x8c, 0x77, 0xd8, 0x77, 0x6d, 0x51, 0xfe, 0xb4, 0xd0, 0x46, 0xc3, 0xc9, 0x8c, 0xc8, 0x01, 0xd2, 0x20, 0x88, 0x39, 0x5c }, 0, "RAVE" }, { { 0x86, 0x78, 0x9a, 0x85, 0xd7, 0x73, 0x4c, 0x05, 0x8e, 0x02, 0xaf, 0x4c, 0x97, 0x2c, 0x61, 0x2d, 0x51, 0x66, 0xfe, 0xf8 }, 6, "GMBL" }, { { 0x0e, 0x8b, 0x30, 0x28, 0xe0, 0xdc, 0x02, 0xda, 0xcf, 0x70, 0xc0, 0x27, 0xf2, 0x91, 0x16, 0x8a, 0x74, 0x86, 0x27, 0xb3 }, 6, "BLOOM" }, { { 0xae, 0x19, 0x61, 0x6a, 0x36, 0x42, 0xe0, 0xb7, 0x07, 0xf7, 0x7c, 0xf5, 0x73, 0x51, 0x59, 0x15, 0x9f, 0x94, 0x22, 0xa9 }, 8, "REVU" }, @@ -69,13 +65,11 @@ { { 0x33, 0x4c, 0xa4, 0xeb, 0x94, 0xa1, 0x93, 0xe2, 0x14, 0x1b, 0x96, 0x84, 0x2d, 0x0d, 0x86, 0x30, 0xb7, 0x15, 0x43, 0x81 }, 0, "LOOKZ" }, { { 0x73, 0x39, 0x1f, 0xb2, 0xdd, 0xfe, 0xdb, 0xee, 0x6d, 0xe8, 0x66, 0xe4, 0xb7, 0x6d, 0x60, 0xf8, 0x52, 0x62, 0x35, 0x75 }, 0, "DOEX" }, { { 0x58, 0x61, 0x97, 0x35, 0x64, 0x6d, 0x94, 0xa8, 0xc9, 0x4b, 0xb1, 0x94, 0xeb, 0xbc, 0xa0, 0x0a, 0xf8, 0x44, 0x67, 0x51 }, 6, "SOCIETY" }, -{ { 0x1a, 0x13, 0x1a, 0x6e, 0x31, 0xa8, 0xbf, 0xff, 0xe5, 0x84, 0xb3, 0x9b, 0x9a, 0xf1, 0x95, 0x02, 0xaf, 0x40, 0x37, 0x48 }, 0, "YAY" }, { { 0x1b, 0x4e, 0x44, 0x23, 0x7b, 0x3e, 0x88, 0x3f, 0x1d, 0x74, 0x06, 0x89, 0xcc, 0xe4, 0xd1, 0x5f, 0x63, 0xa1, 0x62, 0xf9 }, 6, "LOG" }, { { 0x93, 0xe9, 0x1a, 0xbb, 0x2f, 0x08, 0x0a, 0xe9, 0x5d, 0x73, 0xce, 0xfa, 0x2c, 0x33, 0xab, 0xc5, 0x1b, 0x05, 0xd3, 0x8c }, 0, "$CLAW" }, { { 0x09, 0xf5, 0xcd, 0x55, 0x6b, 0x56, 0x25, 0xfd, 0xaf, 0xee, 0xa1, 0x0f, 0x08, 0xac, 0x54, 0xbf, 0x72, 0xf3, 0xa3, 0x2d }, 0, "PIGY" }, { { 0x4f, 0x7c, 0x70, 0xff, 0x69, 0x10, 0xd8, 0xf7, 0x6d, 0xa3, 0xea, 0x4f, 0xc3, 0xb4, 0x65, 0xec, 0x8f, 0x91, 0xc2, 0x1f }, 0, "CNT" }, { { 0xc6, 0xb9, 0xde, 0x78, 0x3c, 0x4c, 0x0d, 0x79, 0xef, 0xd9, 0x43, 0xf3, 0x91, 0xdf, 0x95, 0x84, 0xdc, 0x96, 0x96, 0x13 }, 6, "COPI" }, -{ { 0xa0, 0xc3, 0x9b, 0xb0, 0x51, 0x9a, 0x67, 0x98, 0x9e, 0x5d, 0x8e, 0xea, 0x33, 0xdd, 0x1e, 0xdc, 0x2b, 0x37, 0x88, 0x7f }, 0, "SHIBA" }, { { 0x8e, 0xeb, 0xaa, 0xf7, 0xc0, 0x2f, 0xc9, 0xa8, 0x33, 0x5b, 0x50, 0x66, 0xc2, 0x16, 0xcb, 0xd0, 0x41, 0x1e, 0x69, 0xa9 }, 0, "KIDZ" }, { { 0x53, 0x9a, 0xc0, 0xc3, 0xa8, 0x18, 0x23, 0x50, 0xc5, 0x7a, 0x45, 0xe9, 0xcd, 0xec, 0x0a, 0x3e, 0x24, 0x68, 0x3f, 0x6e }, 6, "FUD" }, { { 0x79, 0x0c, 0x25, 0xf7, 0x51, 0x17, 0x5f, 0x7c, 0xbb, 0x7f, 0xf3, 0x4d, 0xee, 0x67, 0xd4, 0x78, 0xed, 0x3d, 0xd5, 0x80 }, 0, "PPC" }, @@ -97,4 +91,10 @@ { { 0xab, 0x61, 0x6a, 0xc3, 0x78, 0x0a, 0x00, 0xa5, 0xec, 0x73, 0xb9, 0x06, 0x52, 0x39, 0xa2, 0x47, 0xf4, 0xaa, 0xc1, 0x2e }, 0, "NFTC" }, { { 0xe1, 0xca, 0x71, 0xb6, 0xaa, 0xaf, 0x40, 0x4e, 0x62, 0xa8, 0xd3, 0x1b, 0x6b, 0x9a, 0xf4, 0xbf, 0x0f, 0xa1, 0x61, 0x8a }, 6, "EMP" }, { { 0x78, 0x39, 0x47, 0x9b, 0x05, 0x7f, 0x13, 0x95, 0xbc, 0xf0, 0x91, 0xef, 0xcf, 0x72, 0x12, 0x78, 0xe6, 0x5f, 0x76, 0x69 }, 0, "RAG" }, -{ { 0x51, 0xff, 0xe7, 0xe7, 0x4f, 0xa1, 0x87, 0xd5, 0xbb, 0xe4, 0x8b, 0x61, 0xbf, 0x4c, 0x65, 0xbc, 0x82, 0xb3, 0xf7, 0xcb }, 6, "BCG" } +{ { 0x51, 0xff, 0xe7, 0xe7, 0x4f, 0xa1, 0x87, 0xd5, 0xbb, 0xe4, 0x8b, 0x61, 0xbf, 0x4c, 0x65, 0xbc, 0x82, 0xb3, 0xf7, 0xcb }, 6, "BCG" }, +{ { 0xfa, 0x39, 0xf5, 0x9b, 0x51, 0x4f, 0x2d, 0x2f, 0xde, 0x13, 0xc6, 0xdc, 0x15, 0x46, 0x81, 0xc4, 0xef, 0x54, 0xdc, 0xa7 }, 6, "NMKR" }, +{ { 0x3b, 0x34, 0x74, 0xbd, 0x88, 0x62, 0xa7, 0x88, 0xf5, 0x67, 0xc7, 0x39, 0x9d, 0xf9, 0x31, 0x48, 0x96, 0xe0, 0x60, 0x0a }, 6, "WRT" }, +{ { 0x04, 0x93, 0xf4, 0x95, 0x30, 0x89, 0x8e, 0x3d, 0xfe, 0x7d, 0xc0, 0x94, 0x3d, 0x19, 0xbc, 0x1b, 0xdc, 0xb3, 0x6e, 0x10 }, 6, "C3" }, +{ { 0x83, 0x45, 0xbc, 0xd3, 0x13, 0x72, 0x01, 0x6d, 0x70, 0xb5, 0xb3, 0xd3, 0x3f, 0x93, 0x79, 0x9b, 0x26, 0xc4, 0xb2, 0x32 }, 4, "CLAY" }, +{ { 0x73, 0x88, 0x43, 0x9d, 0x27, 0xe1, 0x63, 0xeb, 0x8b, 0xd6, 0xe4, 0xff, 0x68, 0x43, 0xc8, 0xe5, 0x6b, 0xa0, 0xeb, 0x2d }, 8, "AGIX" }, +{ { 0xe1, 0xf1, 0xde, 0x48, 0x36, 0xc3, 0xed, 0xba, 0xb3, 0xee, 0x34, 0xda, 0x74, 0x96, 0x95, 0xf9, 0x83, 0x71, 0xe0, 0xff }, 6, "INDY" } diff --git a/tokenRegistry/top100JsonList_ep321-337.json b/tokenRegistry/top100JsonList.json similarity index 59% rename from tokenRegistry/top100JsonList_ep321-337.json rename to tokenRegistry/top100JsonList.json index ba89b83b..2ebc8d6c 100644 --- a/tokenRegistry/top100JsonList_ep321-337.json +++ b/tokenRegistry/top100JsonList.json @@ -3,900 +3,600 @@ "assetSubject": "a0028f350aaabe0545fdcb56b039bfb08e4bb4d8c4d7c3c7d481c235484f534b59", "name": "HOSKY Token", "ticker": "HOSKY", - "decimals": 0, - "outUTXOs": 1276999, - "rank": 1, - "comment": "" + "decimals": 0 }, { "assetSubject": "af2e27f580f7f08e93190a81f72462f153026d06450924726645891b44524950", "name": "DRIP", "ticker": "DRIP", - "decimals": 6, - "outUTXOs": 1192081, - "rank": 2, - "comment": "" + "decimals": 6 }, { "assetSubject": "9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d7753554e444145", "name": "SUNDAE", "ticker": "SUNDAE", - "decimals": 6, - "outUTXOs": 893387, - "rank": 3, - "comment": "" + "decimals": 6 }, { "assetSubject": "4247d5091db82330100904963ab8d0850976c80d3f1b927e052e07bd546f6b68756e", "name": "Tokhun.io Token", "ticker": "Tokhun", - "decimals": 0, - "outUTXOs": 699913, - "rank": 4, - "comment": "" + "decimals": 0 }, { "assetSubject": "d894897411707efa755a76deb66d26dfd50593f2e70863e1661e98a07370616365636f696e73", "name": "spacecoins", "ticker": "SPACE", - "decimals": 0, - "outUTXOs": 678312, - "rank": 5, - "comment": "" + "decimals": 0 }, { "assetSubject": "29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c64d494e", "name": "Minswap", "ticker": "MIN", - "decimals": 6, - "outUTXOs": 628479, - "rank": 6, - "comment": "" + "decimals": 6 }, { "assetSubject": "afc910d7a306d20c12903979d4935ae4307241d03245743548e767834153484942", "name": "ADA Shiba Inu", "ticker": "ASHIB", - "decimals": 6, - "outUTXOs": 614189, - "rank": 7, - "comment": "" + "decimals": 6 }, { "assetSubject": "5ad8deb64bfec21ad2d96e1270b5873d0c4d0f231b928b4c39eb243561646f736961", "name": "Adosia", "ticker": "ADO", - "decimals": 6, - "outUTXOs": 569573, - "rank": 8, - "comment": "" + "decimals": 6 }, { "assetSubject": "8654e8b350e298c80d2451beb5ed80fc9eee9f38ce6b039fb8706bc34c4f4253544552", "name": "LOBSTER", "ticker": "$LOBSTER", - "decimals": 0, - "outUTXOs": 549856, - "rank": 9, - "comment": "no metadata-registry decimals entry, set to 0 because its optional" + "decimals": 0 }, { "assetSubject": "d030b626219d81673bd32932d2245e0c71ae5193281f971022b23a78436172646f67656f", "name": "Cardogeo", "ticker": "CDOG", - "decimals": 0, - "outUTXOs": 502804, - "rank": 10, - "comment": "no metadata-registry decimals entry, set to 0 because its optional" + "decimals": 0 }, { "assetSubject": "a4da8764a57e66a0085b5bfcde96c89b798d92ee83a75f59237e375b46495245", "name": "FIRE Token", "ticker": "FIRE", - "decimals": 0, - "outUTXOs": 472875, - "rank": 11, - "comment": "no metadata-registry decimals entry, set to 0 because its optional" + "decimals": 0 }, { "assetSubject": "2afb448ef716bfbed1dcb676102194c3009bee5399e93b90def9db6a4249534f4e", "name": "Bison Coin", "ticker": "BISON", - "decimals": 0, - "outUTXOs": 467122, - "rank": 12, - "comment": "" + "decimals": 0 }, { "assetSubject": "f28f457472e539dc75e1598a2beddf49ce5a717998c708f05f5de61044454653", "name": "Defender Silver", "ticker": "DEFS", - "decimals": 0, - "outUTXOs": 466549, - "rank": 13, - "comment": "" + "decimals": 0 }, { "assetSubject": "544571c086d0e5c5022aca9717dd0f438e21190abb48f37b3ae129f047524f57", "name": "GROW Token", "ticker": "GROW", - "decimals": 0, - "outUTXOs": 448153, - "rank": 14, - "comment": "no metadata-registry decimals entry, set to 0 because its optional" + "decimals": 0 }, { "assetSubject": "1a71dc14baa0b4fcfb34464adc6656d0e562571e2ac1bc990c9ce5f6574f4c46", "name": "$WOLF", "ticker": "WOLF", - "decimals": 0, - "outUTXOs": 418730, - "rank": 15, - "comment": "" + "decimals": 0 }, { "assetSubject": "884892bcdc360bcef87d6b3f806e7f9cd5ac30d999d49970e7a903ae5041564941", "name": "PAVIA Token", "ticker": "PAVIA", - "decimals": 0, - "outUTXOs": 387028, - "rank": 16, - "comment": "" + "decimals": 0 }, { "assetSubject": "7f376e3d1cf52e6c4350a1a91c8f8d0f0b63baedd443999ebe8fe57a424f52475a", "name": "BORGZ", "ticker": "BORGZ", - "decimals": 0, - "outUTXOs": 374260, - "rank": 17, - "comment": "" + "decimals": 0 }, { "assetSubject": "987c1f90efe1c95957509b460e0e4f6d6b3f7025a7aca99cd29090374d595448", "name": "MYTH", "ticker": "MYTH", - "decimals": 0, - "outUTXOs": 367995, - "rank": 18, - "comment": "" + "decimals": 0 }, { "assetSubject": "6954264b15bc92d6d592febeac84f14645e1ed46ca5ebb9acdb5c15f5354524950", "name": "StripperCoin", "ticker": "STRIP", - "decimals": 3, - "outUTXOs": 367142, - "rank": 19, - "comment": "" + "decimals": 3 }, { "assetSubject": "6ac8ef33b510ec004fe11585f7c5a9f0c07f0c23428ab4f29c1d7d104d454c44", "name": "MELD", "ticker": "MELD", - "decimals": 6, - "outUTXOs": 365400, - "rank": 20, - "comment": "" + "decimals": 6 }, { "assetSubject": "b0446f1c9105f0cc5bb6bd092f5c3e523e13f8a999b31c870298fa4051554944", "name": "QUID", "ticker": "QUID", - "decimals": 0, - "outUTXOs": 362502, - "rank": 21, - "comment": "" + "decimals": 0 }, { "assetSubject": "025146866af908340247fe4e9672d5ac7059f1e8534696b5f920c9e66362544843", "name": "cbTHC", "ticker": "cbTHC", - "decimals": 6, - "outUTXOs": 359884, - "rank": 22, - "comment": "" + "decimals": 6 }, { "assetSubject": "c68307e7ca850513507f1498862a57c7f4fae7ba8e84b8bc074093a944494253", "name": "DIBS", "ticker": "DIBS", - "decimals": 0, - "outUTXOs": 351933, - "rank": 23, - "comment": "" + "decimals": 0 }, { "assetSubject": "1d7f33bd23d85e1a25d87d86fac4f199c3197a2f7afeb662a0f34e1e776f726c646d6f62696c65746f6b656e", "name": "World Mobile Token", "ticker": "WMT", - "decimals": 6, - "outUTXOs": 329657, - "rank": 24, - "comment": "" + "decimals": 6 }, { "assetSubject": "1f4b1b277c9c001c1522727506a2cfb401a0d0ade069b0241f16f07d4849", "name": "Hosky Inu", "ticker": "HI", - "decimals": 0, - "outUTXOs": 328017, - "rank": 25, - "comment": "no metadata-registry decimals entry, set to 0 because its optional" + "decimals": 0 }, { "assetSubject": "8d0ae3c5b13b47907b16511a540d47436d12dcc96453c0f59089b45142524f4f4d", "name": "BROOM Token", "ticker": "BROOM", - "decimals": 0, - "outUTXOs": 324473, - "rank": 26, - "comment": "" + "decimals": 0 }, { "assetSubject": "d3558649b7874a1a596378515f9b80da63e73f324439ea113d34c9bb42454147", "name": "Beagle Bucks", "ticker": "BEAG", - "decimals": 0, - "outUTXOs": 320400, - "rank": 27, - "comment": "" + "decimals": 0 }, { "assetSubject": "5029eeccd52fef299509d509a8318fd7930c3dffcce1f9f39ff11ef9464743", "name": "FabianGamerCoin", "ticker": "FGC", - "decimals": 0, - "outUTXOs": 320288, - "rank": 28, - "comment": "" + "decimals": 0 }, { "assetSubject": "88691a70bb0fe49cf9124b4f78553c36c09fa6264844e2b2941191734575736b6f", "name": "Eusko", "ticker": "EUS", - "decimals": 0, - "outUTXOs": 317773, - "rank": 29, - "comment": "" + "decimals": 0 }, { "assetSubject": "cfee97ff8359f07a0a395a72b424bc6e030503390d864b86d4e0ecf84b41495a454e", "name": "KAIZEN", "ticker": "KAIZEN", - "decimals": 6, - "outUTXOs": 306770, - "rank": 30, - "comment": "" + "decimals": 6 }, { "assetSubject": "e14fe3ab348f9a6198359481472601f4557b9f86984f40a186a3b1e8434845525259", "name": "CHERRY Token", "ticker": "CHERRY", - "decimals": 0, - "outUTXOs": 302187, - "rank": 31, - "comment": "no metadata-registry decimals entry, set to 0 because its optional" + "decimals": 0 }, { "assetSubject": "e98165a25cd0320b25f22d686268e58e66f855b6d85974947ccd708d414441464f58", "name": "ADAFOX", "ticker": "ADAFOX", - "decimals": 0, - "outUTXOs": 256362, - "rank": 32, - "comment": "" + "decimals": 0 }, { "assetSubject": "da8c30857834c6ae7203935b89278c532b3995245295456f993e1d244c51", "name": "Liqwid DAO Token", "ticker": "LQ", - "decimals": 6, - "outUTXOs": 240656, - "rank": 33, - "comment": "" + "decimals": 6 }, { "assetSubject": "b34b3ea80060ace9427bda98690a73d33840e27aaa8d6edb7f0c757a634e455441", "name": "anetaBTC", "ticker": "cNETA", - "decimals": 0, - "outUTXOs": 235611, - "rank": 34, - "comment": "" + "decimals": 0 }, { "assetSubject": "300ec0d82a79acdc0616fdc0ef615e7deeddb03275e834685e9ee8a65854", "name": "XT", "ticker": "XT", - "decimals": 0, - "outUTXOs": 231375, - "rank": 35, - "comment": "no metadata-registry decimals entry, set to 0 because its optional" + "decimals": 0 }, { "assetSubject": "682fe60c9918842b3323c43b5144bc3d52a23bd2fb81345560d73f634e45574d", "name": "NEWM", "ticker": "NEWM", - "decimals": 6, - "outUTXOs": 219455, - "rank": 36, - "comment": "" + "decimals": 6 }, { "assetSubject": "d3a034e403b98cbdb0adbc8a3144d7779330916e190d387815bb85c650555252", "name": "CatKinson", "ticker": "$PURR", - "decimals": 0, - "outUTXOs": 211831, - "rank": 37, - "comment": "" + "decimals": 0 }, { "assetSubject": "007394e3117755fbb0558b93c54ce3bc6c85770920044ade143dc742505443", "name": "Pocket Change", "ticker": "PTC", - "decimals": 0, - "outUTXOs": 204134, - "rank": 38, - "comment": "" + "decimals": 0 }, { "assetSubject": "a3914cb7a564d010c7b67774ac8720a8ece3a758279b51d8a1c05cc55745444e4553444159", "name": "Wednesday", "ticker": "WDAY", - "decimals": 0, - "outUTXOs": 203357, - "rank": 39, - "comment": "" + "decimals": 0 }, { "assetSubject": "d01794c4604f3c0e544c537bb1f4268c0e81f45880c00c09ebe4b4a74d595354", "name": "Mystery Token", "ticker": "MYST", - "decimals": 0, - "outUTXOs": 196443, - "rank": 40, - "comment": "" + "decimals": 0 }, { "assetSubject": "29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c64d494e74", "name": "Minswap MINt", "ticker": "MINt", - "decimals": 6, - "outUTXOs": 196260, - "rank": 41, - "comment": "" + "decimals": 6 }, { "assetSubject": "8a1cfae21368b8bebbbed9800fec304e95cce39a2a57dc35e2e3ebaa4d494c4b", "name": "MILK", "ticker": "MILK", - "decimals": 0, - "outUTXOs": 190734, - "rank": 42, - "comment": "" + "decimals": 0 }, { "assetSubject": "a89568bb399d0cdc38367e47831c95186f5c79e58174e08a182323964554424643546f6b656e", "name": "ETBFCToken", "ticker": "ETB", - "decimals": 6, - "outUTXOs": 186741, - "rank": 43, - "comment": "" - }, - { - "assetSubject": "c88bbd1848db5ea665b1fffbefba86e8dcd723b5085348e8a8d2260f44414e41", - "name": "DANA", - "ticker": "DANA", - "decimals": 6, - "outUTXOs": 185329, - "rank": 44, - "comment": "" + "decimals": 6 }, { "assetSubject": "47959e79846b8bdcacb91f586408d97e2dff44f31a04f03902cba8185357454554", "name": "SWEET", "ticker": "SWEET", - "decimals": 0, - "outUTXOs": 156822, - "rank": 45, - "comment": "" + "decimals": 0 }, { "assetSubject": "0171c997b8853fde686763d93b36ab8e04ce947bb6aa09a9ee5c4401544f4b454e", "name": "TOKEN", "ticker": "TOKEN", - "decimals": 0, - "outUTXOs": 154442, - "rank": 46, - "comment": "" + "decimals": 0 }, { "assetSubject": "d5dec6074942b36b50975294fd801f7f28c907476b1ecc1b57c916ed524154", "name": "RAT", "ticker": "RAT", - "decimals": 6, - "outUTXOs": 146109, - "rank": 47, - "comment": "" + "decimals": 6 }, { "assetSubject": "8fef2d34078659493ce161a6c7fba4b56afefa8535296a5743f6958741414441", "name": "Aada DAO Token", "ticker": "AADA", - "decimals": 6, - "outUTXOs": 141666, - "rank": 48, - "comment": "" + "decimals": 6 }, { "assetSubject": "0c78f619e54a5d00e143f66181a2c500d0c394b38a10e86cd1a23c5f41444158", "name": "ADAX", "ticker": "ADAX", - "decimals": 0, - "outUTXOs": 134673, - "rank": 49, - "comment": "" + "decimals": 0 }, { "assetSubject": "585cfcbdd0786e961187999e5d5d36b38d1ebc1c4112a0a95a8bd477424c43", "name": "Ibilecoin", "ticker": "BLC", - "decimals": 6, - "outUTXOs": 132248, - "rank": 50, - "comment": "" + "decimals": 6 }, { "assetSubject": "0c442180dd6163682d8e03b271caefb4944a24412bdd07adafb04ccb50494e41434f4c414441", "name": "PinacolADA", "ticker": "Pina", - "decimals": 0, - "outUTXOs": 124376, - "rank": 51, - "comment": "" + "decimals": 0 }, { "assetSubject": "f4d97191f857096b441a410c036f63d6697dde0c71d2755dd664e3024d4b41", "name": "Merkaba", "ticker": "MKA", - "decimals": 5, - "outUTXOs": 119036, - "rank": 52, - "comment": "" + "decimals": 5 }, { "assetSubject": "804f5544c1962a40546827cab750a88404dc7108c0f588b72964754f56594649", "name": "VYFI", "ticker": "VYFI", - "decimals": 6, - "outUTXOs": 117265, - "rank": 53, - "comment": "" - }, - { - "assetSubject": "ae2a0aa5a24b27d9868c4a73b7c08077ac21baade5eca0fa467a2bbd58524159", - "name": "XRAY", - "ticker": "XRAY", - "decimals": 0, - "outUTXOs": 102714, - "rank": 54, - "comment": "no metadata-registry decimals entry, set to 0 because its optional" + "decimals": 6 }, { "assetSubject": "0fd9819a9d7fb414880883f43a42d33458f12bc5f9841cec6457dc155669527553", "name": "Virus", "ticker": "virus", - "decimals": 0, - "outUTXOs": 99330, - "rank": 55, - "comment": "" - }, - { - "assetSubject": "df0172804f8418afc4e5b0a15b8fc78bdc3ca6d179405a7cd194f3b4464c49434b", - "name": "Flickto", - "ticker": "FLICK", - "decimals": 0, - "outUTXOs": 89392, - "rank": 56, - "comment": "no metadata-registry decimals entry, set to 0 because its optional" + "decimals": 0 }, { "assetSubject": "20cd68533b47565f3c61efb39c30fdace9963bfa4c0060b613448e3c50524f584945", "name": "PROXIE", "ticker": "PROXIE", - "decimals": 6, - "outUTXOs": 89360, - "rank": 57, - "comment": "" + "decimals": 6 }, { "assetSubject": "e9c28a71273f825b13f38244ccf1fea97c4025813610d01a7c5d681f436861726c7a20546f6b656e", "name": "Charlz Token", "ticker": "CHRLZ", - "decimals": 0, - "outUTXOs": 86651, - "rank": 58, - "comment": "no metadata-registry decimals entry, set to 0 because its optional" + "decimals": 0 }, { "assetSubject": "6787a47e9f73efe4002d763337140da27afa8eb9a39413d2c39d4286524144546f6b656e73", "name": "RADTokens", "ticker": "RAD", - "decimals": 0, - "outUTXOs": 85105, - "rank": 59, - "comment": "no metadata-registry decimals entry, set to 0 because its optional" + "decimals": 0 }, { "assetSubject": "db30c7905f598ed0154de14f970de0f61f0cb3943ed82c891968480a434c4150", "name": "CLAP", "ticker": "CLAP", - "decimals": 3, - "outUTXOs": 84240, - "rank": 60, - "comment": "" + "decimals": 3 }, { "assetSubject": "aea1ceb3625680e2f7a31ea1a64c9c430c34d8588bf4f8e3c7f9b1dd476f74636869", "name": "Gotchi", "ticker": "GTCHI", - "decimals": 6, - "outUTXOs": 82641, - "rank": 61, - "comment": "" - }, - { - "assetSubject": "14a3455f71c435a04ea1fdb50a3ef4c1cab0e79fb1565627ac66a57552415645", - "name": "Ravendex", - "ticker": "RAVE", - "decimals": 0, - "outUTXOs": 77688, - "rank": 62, - "comment": "" + "decimals": 6 }, { "assetSubject": "2b0a04a7b60132b1805b296c7fcb3b217ff14413991bf76f72663c3067696d62616c", "name": "gimbal", "ticker": "GMBL", - "decimals": 6, - "outUTXOs": 72590, - "rank": 63, - "comment": "" + "decimals": 6 }, { "assetSubject": "4c17b7009448a33d1834b0946ea752ecd0cc61c7bb25cd9ff18cff58426c6f6f6d", "name": "Bloom", "ticker": "BLOOM", - "decimals": 6, - "outUTXOs": 69842, - "rank": 64, - "comment": "" + "decimals": 6 }, { "assetSubject": "94cbb4fcbcaa2975779f273b263eb3b5f24a9951e446d6dc4c13586452455655", "name": "Revuto", "ticker": "REVU", - "decimals": 8, - "outUTXOs": 64133, - "rank": 65, - "comment": "" + "decimals": 8 }, { "assetSubject": "63766427b4499dd678cb8b715dec3265dd292279ce7779447e3651e54b4f5a", "name": "Politikoz Token", "ticker": "KOZ", - "decimals": 0, - "outUTXOs": 62748, - "rank": 66, - "comment": "" + "decimals": 0 }, { "assetSubject": "885742cd7e0dad321622b5d3ad186797bd50c44cbde8b48be1583fbd534b554c4c", "name": "SKULL", "ticker": "SKULL", - "decimals": 0, - "outUTXOs": 53781, - "rank": 67, - "comment": "no metadata-registry decimals entry, set to 0 because its optional" + "decimals": 0 }, { "assetSubject": "f7c777fdd4531cf1c477551360e45b9684073c05c2fa61334f8f9add5665726974726565546f6b656e", "name": "VeritreeToken", "ticker": "TREES", - "decimals": 0, - "outUTXOs": 50107, - "rank": 68, - "comment": "" + "decimals": 0 }, { "assetSubject": "aa2797739e4f4a1efd5346998febff59909e425b5fddb1b0ec4a24f84c6f6f6b7a", "name": "Lookz", "ticker": "LOOKZ", - "decimals": 0, - "outUTXOs": 49478, - "rank": 69, - "comment": "" + "decimals": 0 }, { "assetSubject": "dca54ecf37b0e3af2fdfd336e1d21fadcc45b3261b0f73a095631dfe444f4558", "name": "DOEX", "ticker": "DOEX", - "decimals": 0, - "outUTXOs": 45130, - "rank": 70, - "comment": "" + "decimals": 0 }, { "assetSubject": "25f0fc240e91bd95dcdaebd2ba7713fc5168ac77234a3d79449fc20c534f4349455459", "name": "SOCIETY", "ticker": "SOCIETY", - "decimals": 6, - "outUTXOs": 45117, - "rank": 71, - "comment": "" - }, - { - "assetSubject": "57684adcb032c8dbc40179841bed987d8dee7472617a0e5c25ef414059617953776170", - "name": "YaySwap", - "ticker": "YAY", - "decimals": 0, - "outUTXOs": 40138, - "rank": 72, - "comment": "no metadata-registry decimals entry, set to 0 because its optional" + "decimals": 6 }, { "assetSubject": "c9f955eeffa84e42363b4992281d32dd2f9239153d6c66420a9acc154c4f47", "name": "Life Log Token", "ticker": "LOG", - "decimals": 6, - "outUTXOs": 35685, - "rank": 73, - "comment": "" + "decimals": 6 }, { "assetSubject": "240fb00eff73acc51c09e81dae6628c4bedb9964151d45e3faed874f434c4157", "name": "Claw Token", "ticker": "$CLAW", - "decimals": 0, - "outUTXOs": 34818, - "rank": 74, - "comment": "" + "decimals": 0 }, { "assetSubject": "2aa9c1557fcf8e7caa049fa0911a8724a1cdaf8037fe0b431c6ac66450494759546f6b656e", "name": "PIGY Token", "ticker": "PIGY", - "decimals": 0, - "outUTXOs": 34677, - "rank": 75, - "comment": "no metadata-registry decimals entry, set to 0 because its optional" + "decimals": 0 }, { "assetSubject": "2c96f49b6e6e32ae69a182e85b74db4edfc9539496a13ab76d1258fa434e54", "name": "Cardano Native Token", "ticker": "CNT", - "decimals": 0, - "outUTXOs": 34416, - "rank": 76, - "comment": "" + "decimals": 0 }, { "assetSubject": "b6a7467ea1deb012808ef4e87b5ff371e85f7142d7b356a40d9b42a0436f726e75636f70696173205b76696120436861696e506f72742e696f5d", "name": "Cornucopias Token", "ticker": "COPI", - "decimals": 6, - "outUTXOs": 32843, - "rank": 77, - "comment": "" - }, - { - "assetSubject": "208a2ca888886921513cb777bb832a8dc685c04de990480151f1215053484942414441", - "name": "SHIBADA", - "ticker": "SHIBA", - "decimals": 0, - "outUTXOs": 32643, - "rank": 78, - "comment": "no metadata-registry decimals entry, set to 0 because its optional" + "decimals": 6 }, { "assetSubject": "c4c00fbd8fa227442a5e7cdecde33b24588494d05a2c50fda8938c6d4b49445a", "name": "Kidz Coin", "ticker": "KIDZ", - "decimals": 0, - "outUTXOs": 30832, - "rank": 79, - "comment": "" + "decimals": 0 }, { "assetSubject": "dbc31b04d90b37332813cb4cee3e8f79994643d899a5366797e745ee465544", "name": "FudCoin", "ticker": "FUD", - "decimals": 6, - "outUTXOs": 30419, - "rank": 80, - "comment": "" + "decimals": 6 }, { "assetSubject": "d0af056c509b6b1133cd83a750b7245e561169281fde3df1cb6e2d96506f6f6c5065656b436f696e", "name": "PoolPeekCoin", "ticker": "PPC", - "decimals": 0, - "outUTXOs": 30073, - "rank": 81, - "comment": "" + "decimals": 0 }, { "assetSubject": "8f52f6a88acf6127bc4758a16b6047afc4da7887feae121ec217b75a534e4f57", "name": "SNOW", "ticker": "SNOW", - "decimals": 0, - "outUTXOs": 30071, - "rank": 82, - "comment": "" + "decimals": 0 }, { "assetSubject": "2441ab3351c3b80213a98f4e09ddcf7dabe4879c3c94cc4e7205cb6346495245", "name": "FIRE", "ticker": "FIRE", - "decimals": 0, - "outUTXOs": 29214, - "rank": 83, - "comment": "" + "decimals": 0 }, { "assetSubject": "c7dcfa416c127f630b263c7e0fe0564430cfa9c56bba43e1a37c6915474f4b4559", "name": "GoKey", "ticker": "GOKEY", - "decimals": 0, - "outUTXOs": 27480, - "rank": 84, - "comment": "" + "decimals": 0 }, { "assetSubject": "97747aa3c33fdfe4b5faa7bb8b4534932c6d980cb13c14c5a547e7ca70757272414441", "name": "purrADA", "ticker": "purrADA", - "decimals": 6, - "outUTXOs": 27445, - "rank": 85, - "comment": "" + "decimals": 6 }, { "assetSubject": "ccb3577601d6cf0e021288871112926338bee685c6c37eeadf6dddd943617264616e6961466f756e646572426c7565", "name": "CardaniaFounderBlue", "ticker": "CDFC5", - "decimals": 0, - "outUTXOs": 26256, - "rank": 86, - "comment": "" + "decimals": 0 }, { "assetSubject": "ccb3577601d6cf0e021288871112926338bee685c6c37eeadf6dddd943617264616e6961466f756e646572526564", "name": "CardaniaFounderRed", "ticker": "CDFC4", - "decimals": 0, - "outUTXOs": 26198, - "rank": 87, - "comment": "" + "decimals": 0 }, { "assetSubject": "1f4b1b277c9c001c1522727506a2cfb401a0d0ade069b0241f16f07d484953", "name": "Hosky Inu Silver", "ticker": "HIS", - "decimals": 0, - "outUTXOs": 25973, - "rank": 88, - "comment": "no metadata-registry decimals entry, set to 0 because its optional" + "decimals": 0 }, { "assetSubject": "ccb3577601d6cf0e021288871112926338bee685c6c37eeadf6dddd943617264616e6961466f756e646572477265656e", "name": "CardaniaFounderGreen", "ticker": "CDFC6", - "decimals": 0, - "outUTXOs": 25479, - "rank": 89, - "comment": "" + "decimals": 0 }, { "assetSubject": "b4273f1d8d0021d188784c3d72dc514f602b7ab8cfb87e3134550c42446f6765414441", "name": "DogeADA", "ticker": "DGADA", - "decimals": 0, - "outUTXOs": 24277, - "rank": 90, - "comment": "" + "decimals": 0 }, { "assetSubject": "133fac9e153194428eb0919be39837b42b9e977fc7298f3ff1b76ef95055444759", "name": "$PUDGY Token", "ticker": "PUDGY", - "decimals": 0, - "outUTXOs": 23162, - "rank": 91, - "comment": "" + "decimals": 0 }, { "assetSubject": "f555c46bad0731d080c9381d7fff6f82839946a66bd070d185e1ea2f42444f4745", "name": "BlackDoge", "ticker": "BDOGE", - "decimals": 0, - "outUTXOs": 22502, - "rank": 92, - "comment": "" + "decimals": 0 }, { "assetSubject": "1dd1a7dde0e1e82761325ee5f4719d0d4b7c24dfba77d9bee01eed4b4d454f57", "name": "MEOW", "ticker": "MEOW", - "decimals": 6, - "outUTXOs": 22207, - "rank": 93, - "comment": "" + "decimals": 6 }, { "assetSubject": "a00fdf4fb9ab6c8c2bd1533a2f14855edf12aed5ecbf96d4b5f5b9394334", "name": "Cardano Crocs Club Coin", "ticker": "C4", - "decimals": 0, - "outUTXOs": 21903, - "rank": 94, - "comment": "no metadata-registry decimals entry, set to 0 because its optional" + "decimals": 0 }, { "assetSubject": "f4364875e75320d405ceadebdf0db63fadaff55c72d4ff6b82f0676a434152474f", "name": "Cardano Gold", "ticker": "CARGO", - "decimals": 6, - "outUTXOs": 21152, - "rank": 95, - "comment": "" + "decimals": 6 }, { "assetSubject": "59e31d17e4d212ea35df6088e0395455c40f5ad463d161497a89c567426162795365616c", "name": "BabySeal", "ticker": "BSEAL", - "decimals": 0, - "outUTXOs": 21099, - "rank": 96, - "comment": "no metadata-registry decimals entry, set to 0 because its optional" + "decimals": 0 }, { "assetSubject": "b0af30edf2c7f11465853821137e0a6ebc395cab71ee39c24127ffb44e465443", "name": "NFT Creative Coin", "ticker": "NFTC", - "decimals": 0, - "outUTXOs": 21090, - "rank": 97, - "comment": "" + "decimals": 0 }, { "assetSubject": "6c8642400e8437f737eb86df0fc8a8437c760f48592b1ba8f5767e81456d706f7761", "name": "Empowa", "ticker": "EMP", - "decimals": 6, - "outUTXOs": 18610, - "rank": 98, - "comment": "" + "decimals": 6 }, { "assetSubject": "ca942cb8bb5d1ef750766ded355f320880539111f10efa2b1a478ff9524147", "name": "RaggieCoin", "ticker": "RAG", - "decimals": 0, - "outUTXOs": 18440, - "rank": 99, - "comment": "" + "decimals": 0 }, { "assetSubject": "0c92aabef5a8f91a36470d0762806c165c0d04aa992541e25d55486a424347", "name": "Blockchaingames", "ticker": "BCG", - "decimals": 6, - "outUTXOs": 18339, - "rank": 100, - "comment": "" + "decimals": 6 + }, + { + "assetSubject": "5dac8536653edc12f6f5e1045d8164b9f59998d3bdc300fc928434894e4d4b52", + "name": "NMKR", + "ticker": "NMKR", + "decimals": 6 + }, + { + "assetSubject": "c0ee29a85b13209423b10447d3c2e6a50641a15c57770e27cb9d507357696e67526964657273", + "name": "WingRiders Governance Token", + "ticker": "WRT", + "decimals": 6 + }, + { + "assetSubject": "8e51398904a5d3fc129fbf4f1589701de23c7824d5c90fdb9490e15a434841524c4933", + "name": "CHARLI3", + "ticker": "C3", + "decimals": 6 + }, + { + "assetSubject": "38ad9dc3aec6a2f38e220142b9aa6ade63ebe71f65e7cc2b7d8a8535434c4159", + "name": "CLAY", + "ticker": "CLAY", + "decimals": 4 + }, + { + "assetSubject": "f43a62fdc3965df486de8a0d32fe800963589c41b38946602a0dc53541474958", + "name": "SingularityNet AGIX Token", + "ticker": "AGIX", + "decimals": 8 + }, + { + "assetSubject": "533bb94a8850ee3ccbe483106489399112b74c905342cb1792a797a0494e4459", + "name": "Indigo DAO Token", + "ticker": "INDY", + "decimals": 6 } ] From 09684ca286b741402d6e8353824450671cdf063a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1n=20Maz=C3=A1k?= <42575685+janmazak@users.noreply.github.com> Date: Thu, 2 Feb 2023 10:12:48 +0100 Subject: [PATCH 003/105] update: change CIP36 strings in UI (#33) * update: change strings in UI * update: do not refer to 'governance' in CIP36 documentation * update version to 6.0.2 --- CHANGELOG.md | 12 ++++++------ Makefile | 2 +- ...tration.md => ins_sign_cip36_registration.md} | 16 ++++++++-------- doc/ins_sign_tx.md | 8 ++++---- src/securityPolicy.c | 2 +- src/signTx.c | 6 +++--- src/signTxAuxData.h | 2 +- src/signTxGovernanceVotingRegistration.c | 12 ++++++------ src/signTxGovernanceVotingRegistration.h | 2 +- 9 files changed, 31 insertions(+), 31 deletions(-) rename doc/{ins_sign_governance_voting_registration.md => ins_sign_cip36_registration.md} (70%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 356cdf6c..f535d676 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,19 +6,19 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [6.0.1](TBD) - [TBD] +## [6.0.2](TBD) - [TBD] -Support for governance voting (CIP-0036) +Support for CIP-36 voting ### Added -- export of governance voting keys (1694'/1815'/...) -- support for governance voting (signing of vote-cast fragments with 1694 keys) -- support for CIP-36 features (governance voting registration in transaction auxiliary data) +- export of vote keys (1694'/1815'/...) +- support for CIP-36 voting (signing of vote-cast fragments with 1694 keys) +- support for CIP-36 registrations (in transaction auxiliary data) ### Changed -- API for Catalyst voting registration (it is still possible to use CIP-0015 in auxiliary data) +- API for Catalyst voting registration (it is still possible to use CIP-15 in auxiliary data) - updated list of native tokens recognized by the app with correct decimal places diff --git a/Makefile b/Makefile index f5ca3bb1..db2fd81b 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ APPNAME = "Cardano ADA" APPVERSION_M = 6 APPVERSION_N = 0 -APPVERSION_P = 1 +APPVERSION_P = 2 APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" ifeq ($(BOLOS_SDK),) diff --git a/doc/ins_sign_governance_voting_registration.md b/doc/ins_sign_cip36_registration.md similarity index 70% rename from doc/ins_sign_governance_voting_registration.md rename to doc/ins_sign_cip36_registration.md index 4e12d963..9940ce0c 100644 --- a/doc/ins_sign_governance_voting_registration.md +++ b/doc/ins_sign_cip36_registration.md @@ -1,10 +1,10 @@ -# Governance Voting Key Registration +# CIP36 Voting Key Registration ## Description -Cardano uses a sidechain for its governance voting. One needs to "register" to participate on this sidechain by submitting a registration transaction on the Cardano blockchain. This is done by submitting a transaction with specific auxiliary data attached to the transaction body. These auxiliary data contain a signature by user's staking key, hence serialization of the it by Ledger is required which after confirming by the user returns that signature for the client software to be able to assemble the full serialized transaction. +Cardano uses a sidechain for voting (initially used only for Catalyst, but CIP-36 allows other voting purposes). One needs to "register" to participate on this sidechain by submitting a registration transaction on the Cardano blockchain. This is done by submitting a transaction with specific auxiliary data attached to the transaction body. These auxiliary data contain a signature by user's staking key, hence serialization of the it by Ledger is required which after confirming by the user returns that signature for the client software to be able to assemble the full serialized transaction. -For more details about governance voting registration see [CIP-0036](https://cips.cardano.org/cips/cip36/). +For more details about voting registration see [CIP-0036](https://cips.cardano.org/cips/cip36/). --- @@ -17,7 +17,7 @@ In the following list of APDU messages (which are to be sent in the listed order | P1 | `0x08` | | P2 | (specific for each subcall) | -All but the last response are empty. The last response contains the overall auxiliary data hash and the signature needed for the client to assemble the governance voting registration auxiliary data. +All but the last response are empty. The last response contains the overall auxiliary data hash and the signature needed for the client to assemble the CIP36 registration auxiliary data. --- @@ -29,7 +29,7 @@ P2 = `0x36` |Field| Length | Comments| |-----|--------|---------| -|Governance voting registration format | 1 | 0x01 or 0x02 for CIP15 and CIP36, respectively| +|Registration format | 1 | 0x01 or 0x02 for CIP15 and CIP36, respectively| |Number of delegations | 4 | big endian | --- @@ -139,7 +139,7 @@ Data must be empty. |Field|Length| Comments| |-----|-----|-----| -| Auxiliary data hash | 32 | Hash of the governance voting registration auxiliary data| -| Signature |64| Governance voting registration signature by the staking key that has been supplied| +| Auxiliary data hash | 32 | Hash of the registration auxiliary data| +| Signature |64| Voting registration signature by the staking key that has been supplied| -Note: governance voting registration auxiliary data is serialized in the [Mary-era format](https://github.com/input-output-hk/cardano-ledger-specs/blob/dcdbc38eb9caea16485827bd095d5adcdcca0aba/shelley-ma/shelley-ma-test/cddl-files/shelley-ma.cddl#L214), where the array of auxiliary scripts is fixed to an empty array. +Note: voting registration auxiliary data is serialized in the [Mary-era format](https://github.com/input-output-hk/cardano-ledger-specs/blob/dcdbc38eb9caea16485827bd095d5adcdcca0aba/shelley-ma/shelley-ma-test/cddl-files/shelley-ma.cddl#L214), where the array of auxiliary scripts is fixed to an empty array. diff --git a/doc/ins_sign_tx.md b/doc/ins_sign_tx.md index 3abd027e..dd5f1ca3 100644 --- a/doc/ins_sign_tx.md +++ b/doc/ins_sign_tx.md @@ -86,7 +86,7 @@ Optional. |Field|Value| |-----|-----| | P1 | `0x08` | -| P2 | (unused / see [Governance Voting Registration](ins_sign_governance_voting_registration.md)) | +| P2 | (unused / see [CIP-36 Voting Registration](ins_sign_cip36_registration.md)) | **Data for AUX_DATA_TYPE_ARBITRARY_HASH** @@ -98,13 +98,13 @@ So only the hash is transferred and displayed and the user has to use other mean | Auxiliary data type | 1 | `AUX_DATA_TYPE_ARBITRARY_HASH=0x00` | | Auxiliary data hash | 32 | | -**Data for AUX_DATA_TYPE_GOVERNANCE_VOTING_REGISTRATION** +**Data for AUX_DATA_TYPE_CIP36_REGISTRATION** |Field| Length | Comments| |-----|--------|---------| -| Auxiliary data type | 1 | `AUX_DATA_TYPE_GOVERNANCE_VOTING_REGISTRATION=0x01` | +| Auxiliary data type | 1 | `AUX_DATA_TYPE_CIP36_REGISTRATION=0x01` | -This only describes the initial message. All the data for this type of auxiliary data are obtained via a series of additional APDU messages; see [Governance Voting Registration](ins_sign_governance_voting_registration.md) for the details. +This only describes the initial message. All the data for this type of auxiliary data are obtained via a series of additional APDU messages; see [CIP-36 Voting Registration](ins_sign_cip36_registration.md) for the details. ### Set UTxO inputs diff --git a/src/securityPolicy.c b/src/securityPolicy.c index ea676bae..b4838a4c 100644 --- a/src/securityPolicy.c +++ b/src/securityPolicy.c @@ -1541,7 +1541,7 @@ security_policy_t policyForSignTxAuxData(aux_data_type_t auxDataType) SHOW_IF(app_mode_expert()); ALLOW(); - case AUX_DATA_TYPE_GOVERNANCE_VOTING_REGISTRATION: + case AUX_DATA_TYPE_CIP36_REGISTRATION: // this is the policy for the initial prompt // details of the registration are governed by separate policies // (see policyForGovernanceVotingRegistration...) diff --git a/src/signTx.c b/src/signTx.c index 350bba6b..c36f8d2d 100644 --- a/src/signTx.c +++ b/src/signTx.c @@ -742,7 +742,7 @@ static void signTx_handleAuxDataGovernanceVotingRegistration_ui_runStep() UI_STEP(HANDLE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_STEP_DISPLAY) { ui_displayPrompt( "Register governance", - "voting key?", + "vote key?", this_fn, respond_with_user_reject ); @@ -794,7 +794,7 @@ static void signTx_handleAuxDataAPDU(uint8_t p2, const uint8_t* wireDataBuffer, break; } - case AUX_DATA_TYPE_GOVERNANCE_VOTING_REGISTRATION: + case AUX_DATA_TYPE_CIP36_REGISTRATION: break; default: @@ -823,7 +823,7 @@ static void signTx_handleAuxDataAPDU(uint8_t p2, const uint8_t* wireDataBuffer, signTx_handleAuxDataArbitraryHash_ui_runStep(); break; } - case AUX_DATA_TYPE_GOVERNANCE_VOTING_REGISTRATION: + case AUX_DATA_TYPE_CIP36_REGISTRATION: // select UI step switch (policy) { #define CASE(POLICY, UI_STEP) case POLICY: {ctx->ui_step=UI_STEP; break;} diff --git a/src/signTxAuxData.h b/src/signTxAuxData.h index 44060eb0..d416192b 100644 --- a/src/signTxAuxData.h +++ b/src/signTxAuxData.h @@ -3,7 +3,7 @@ typedef enum { AUX_DATA_TYPE_ARBITRARY_HASH = 0, - AUX_DATA_TYPE_GOVERNANCE_VOTING_REGISTRATION = 1, + AUX_DATA_TYPE_CIP36_REGISTRATION = 1, } aux_data_type_t; #endif // H_CARDANO_APP_SIGN_TX_AUX_DATA diff --git a/src/signTxGovernanceVotingRegistration.c b/src/signTxGovernanceVotingRegistration.c index 42ad8daf..b3eb8f8d 100644 --- a/src/signTxGovernanceVotingRegistration.c +++ b/src/signTxGovernanceVotingRegistration.c @@ -231,8 +231,8 @@ static void _displayVotingKey(ui_callback_fn_t callback) case DELEGATION_KEY: { STATIC_ASSERT(SIZEOF(subctx->stateData.delegation.votingPubKey) == GOVERNANCE_VOTING_PUBLIC_KEY_LENGTH, "wrong voting public key size"); ui_displayBech32Screen( - "Voting public key", - "gov_vk", + "Vote public key", + "cvote_vk", subctx->stateData.delegation.votingPubKey, GOVERNANCE_VOTING_PUBLIC_KEY_LENGTH, callback ); @@ -240,7 +240,7 @@ static void _displayVotingKey(ui_callback_fn_t callback) } case DELEGATION_PATH: { ui_displayPathScreen( - "Voting public key", + "Vote public key", &subctx->stateData.delegation.votingPubKeyPath, callback ); @@ -270,7 +270,7 @@ static void signTxGovernanceVotingRegistration_handleVotingKey_ui_runStep() UI_STEP(HANDLE_VOTING_KEY_STEP_WARNING) { ui_displayPaginatedText( "WARNING:", - "unusual voting key", + "unusual vote key", this_fn ); } @@ -375,7 +375,7 @@ static void signTxGovernanceVotingRegistration_handleDelegation_ui_runStep() UI_STEP(HANDLE_VOTING_KEY_STEP_WARNING) { ui_displayPaginatedText( "WARNING:", - "unusual voting key", + "unusual vote key", this_fn ); } @@ -912,7 +912,7 @@ static void signTxGovernanceVotingRegistration_handleConfirm_ui_runStep() // confirming this means the signature being sent out of the device // so we want to show it in non-expert mode too ui_displayPrompt( - "Confirm voting key", + "Confirm vote key", "registration?", this_fn, respond_with_user_reject diff --git a/src/signTxGovernanceVotingRegistration.h b/src/signTxGovernanceVotingRegistration.h index 933a176f..bd304df6 100644 --- a/src/signTxGovernanceVotingRegistration.h +++ b/src/signTxGovernanceVotingRegistration.h @@ -11,7 +11,7 @@ #define GOVERNANCE_VOTING_PUBLIC_KEY_LENGTH 32 // SIGN_STAGE_AUX_DATA = 24 -// AUX_DATA_TYPE_GOVERNANCE_VOTING_REGISTRATION = 1 +// AUX_DATA_TYPE_CIP36_REGISTRATION = 1 typedef enum { STATE_GOVERNANCE_VOTING_REGISTRATION_INIT = 2410, STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_KEY = 2411, From 192d6de462b9b7505c29513d06c36aca20800655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1n=20Maz=C3=A1k?= <42575685+janmazak@users.noreply.github.com> Date: Wed, 1 Mar 2023 11:27:14 +0100 Subject: [PATCH 004/105] addition of native tokens, refactoring according to CIP-36 changes (#34) * refactor: rename token list file * update: add tokens * update build instructions * refactor: no 'governance' for cip36 * fix: spelling --- .gitignore | 1 + CHANGELOG.md | 2 +- Dockerfile | 81 ---- Makefile | 4 +- doc/build.md | 8 +- doc/ins_sign_cip36_registration.md | 10 +- doc/ins_sign_tx.md | 4 +- fuzz/CMakeLists.txt | 2 +- src/addressUtilsByron.c | 2 +- src/addressUtilsShelley_test.c | 9 + src/auxDataHashBuilder.c | 164 ++++---- src/auxDataHashBuilder.h | 70 +-- src/auxDataHashBuilder_test.c | 78 ++-- src/base58.c | 1 + src/base58_test.c | 1 + src/bech32.c | 1 + src/bech32_test.c | 2 + src/bip44.c | 26 +- src/bip44.h | 16 +- src/cardano.h | 2 +- src/errors.h | 2 +- src/handlers.c | 4 +- src/messageSigning.c | 8 +- src/messageSigning.h | 6 +- src/securityPolicy.c | 48 +-- src/securityPolicy.h | 22 +- src/{signGovernanceVote.c => signCVote.c} | 38 +- src/{signGovernanceVote.h => signCVote.h} | 14 +- src/signTx.c | 56 +-- src/signTx.h | 6 +- src/signTxAuxData.h | 2 +- ...gistration.c => signTxCVoteRegistration.c} | 398 +++++++++--------- src/signTxCVoteRegistration.h | 70 +++ src/signTxGovernanceVotingRegistration.h | 70 --- src/signTxMint.c | 4 +- src/signTxOutput.c | 6 +- src/signTxPoolRegistration.c | 4 +- src/signTxUtils.c | 3 +- src/state.h | 4 +- src/textUtils.c | 1 + src/tokens_test.c | 22 +- src/txHashBuilder.c | 4 +- src/txHashBuilder_test.c | 3 +- tokenRegistry/convert.py | 2 +- .../{top100JsonList.json => tokenList.json} | 12 + tokenRegistry/token_data.c | 4 +- 46 files changed, 623 insertions(+), 674 deletions(-) delete mode 100644 Dockerfile rename src/{signGovernanceVote.c => signCVote.c} (91%) rename src/{signGovernanceVote.h => signCVote.h} (73%) rename src/{signTxGovernanceVotingRegistration.c => signTxCVoteRegistration.c} (56%) create mode 100644 src/signTxCVoteRegistration.h delete mode 100644 src/signTxGovernanceVotingRegistration.h rename tokenRegistry/{top100JsonList.json => tokenList.json} (98%) diff --git a/.gitignore b/.gitignore index eef45f38..828dc9c3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ ledger bin +build debug dep obj diff --git a/CHANGELOG.md b/CHANGELOG.md index f535d676..7c5a28b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [6.0.2](TBD) - [TBD] +## [6.0.3](TBD) - [TBD] Support for CIP-36 voting diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index ca21e882..00000000 --- a/Dockerfile +++ /dev/null @@ -1,81 +0,0 @@ -FROM ubuntu:20.04 -ENV LANG C.UTF-8 - -ARG DEBIAN_FRONTEND=noninteractive - -ARG LLVM_VERSION=12 - -RUN apt-get update && apt-get upgrade -qy && \ - apt-get install -qy \ - astyle\ - clang-$LLVM_VERSION \ - clang-tools-$LLVM_VERSION \ - clang-format-$LLVM_VERSION \ - cmake \ - curl \ - doxygen \ - git \ - lcov \ - libbsd-dev \ - libcmocka0 \ - libcmocka-dev \ - lld-$LLVM_VERSION \ - make \ - protobuf-compiler \ - python-is-python3 \ - python3 \ - python3-pip && \ - apt-get autoclean -y && \ - apt-get autoremove -y && \ - apt-get clean - -# Create generic clang & lld symbolic links to their installed version -RUN cd /usr/bin && \ - find . -name "*-"$LLVM_VERSION | sed "s/^\(.*\)\(-"$LLVM_VERSION"\)$/ln -s \1\2 \1/" | sh - -# ARM Embedded Toolchain -# Integrity is checked using the MD5 checksum provided by ARM at https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads -RUN curl -sSfL -o arm-toolchain.tar.bz2 "https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu-rm/10.3-2021.10/gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2" && \ - echo 2383e4eb4ea23f248d33adc70dc3227e arm-toolchain.tar.bz2 > /tmp/arm-toolchain.md5 && \ - md5sum --check /tmp/arm-toolchain.md5 && rm /tmp/arm-toolchain.md5 && \ - tar xf arm-toolchain.tar.bz2 -C /opt && \ - rm arm-toolchain.tar.bz2 - -# Adding GCC to PATH and defining rustup/cargo home directories -ENV PATH=/opt/gcc-arm-none-eabi-10.3-2021.10/bin:$PATH \ - RUSTUP_HOME=/opt/rustup \ - CARGO_HOME=/opt/.cargo - -# Install rustup to manage rust toolchains -RUN curl https://sh.rustup.rs -sSf | \ - sh -s -- --default-toolchain stable -y - -# Adding cargo binaries to PATH -ENV PATH=${CARGO_HOME}/bin:${PATH} - -# Adding ARMV6M target to the default toolchain -RUN rustup target add thumbv6m-none-eabi - -# Python packages commonly used by apps -RUN pip3 install ledgerblue pytest - -ARG GIT_SERVER=https://github.com/LedgerHQ - -# Latest Nano S SDK -ENV NANOS_SDK=/opt/nanos-secure-sdk -RUN git clone --branch 2.1.0 --depth 1 "$GIT_SERVER/nanos-secure-sdk.git" "$NANOS_SDK" - -# Latest Nano X SDK -ENV NANOX_SDK=/opt/nanox-secure-sdk -RUN git clone --branch 2.0.2-2 --depth 1 "$GIT_SERVER/nanox-secure-sdk.git" "$NANOX_SDK" - -# Latest Nano S+ SDK -ENV NANOSP_SDK=/opt/nanosplus-secure-sdk -RUN git clone --branch 1.0.4 --depth 1 "$GIT_SERVER/nanosplus-secure-sdk.git" "$NANOSP_SDK" - -# Default SDK -ENV BOLOS_SDK=${NANOS_SDK} - -WORKDIR /app - -CMD ["/usr/bin/env", "bash"] diff --git a/Makefile b/Makefile index db2fd81b..d5ee3f7e 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ APPNAME = "Cardano ADA" APPVERSION_M = 6 APPVERSION_N = 0 -APPVERSION_P = 2 +APPVERSION_P = 3 APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" ifeq ($(BOLOS_SDK),) @@ -176,7 +176,7 @@ seed: ############## format: - astyle --options=.astylerc "src/*.h" "src/*.c" --exclude=src/glyphs.h --exclude=src/glyphs.c + astyle --options=.astylerc "src/*.h" "src/*.c" --exclude=src/glyphs.h --exclude=src/glyphs.c --ignore-exclude-errors ############## diff --git a/doc/build.md b/doc/build.md index 59fe04e3..14a11485 100644 --- a/doc/build.md +++ b/doc/build.md @@ -3,11 +3,9 @@ ## Dependencies - Install Docker -- Update [Dockerfile](../Dockerfile) if needed: check https://github.com/LedgerHQ/ledger-app-builder/blob/master/Dockerfile. -- Create Docker image - - `docker build -t ledger-app-builder-cardano:latest .` +- Pull the required containers as discussed in https://github.com/LedgerHQ/ledger-app-builder/ (lite container is sufficient for a C build): + `sudo docker pull ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest` ## Compiling the app @@ -19,7 +17,7 @@ Based on https://developers.ledger.com/docs/nano-app/build/. - Create container with the image - `docker run --rm -ti -v "$(realpath .):/app" ledger-app-builder-cardano:latest` + `docker run --rm -ti -v "$(realpath .):/app" --user $(id -u $USER):$(id -g $USER) ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest` - Run make commands diff --git a/doc/ins_sign_cip36_registration.md b/doc/ins_sign_cip36_registration.md index 9940ce0c..9fe21c43 100644 --- a/doc/ins_sign_cip36_registration.md +++ b/doc/ins_sign_cip36_registration.md @@ -1,4 +1,4 @@ -# CIP36 Voting Key Registration +# CIP36 Vote Key Registration ## Description @@ -34,7 +34,7 @@ P2 = `0x36` --- -**Voting key** +**Vote key** A single APDU with voting key is sent if the number of delegations specified in the init APDU is 0 (otherwise no such APDU is allowed). @@ -45,7 +45,7 @@ P2 = `0x30` |Field| Length | Comments| |-----|--------|---------| |Key type | 1 | 0x01 or 0x02 if a 32-byte key or its derivation path follows | -|Voting public key: bytestring or BIP44 derivation path | | (depends on previous line) | +|Vote public key: bytestring or BIP44 derivation path | | (depends on previous line) | **Delegation** @@ -59,7 +59,7 @@ P2 = `0x37` |Field| Length | Comments| |-----|--------|---------| |Key type | 1 | 0x01 or 0x02 if a 32-byte key or its derivation path follows | -|Voting public key: bytestring or BIP44 derivation path | | (depends on previous line) | +|Vote public key: bytestring or BIP44 derivation path | | (depends on previous line) | |Weight | 4 | big endian | --- @@ -76,7 +76,7 @@ P2 = `0x31` --- -**Voting rewards address** +**Voting rewards payment address** P2 = `0x32` diff --git a/doc/ins_sign_tx.md b/doc/ins_sign_tx.md index dd5f1ca3..bbaafa4b 100644 --- a/doc/ins_sign_tx.md +++ b/doc/ins_sign_tx.md @@ -98,11 +98,11 @@ So only the hash is transferred and displayed and the user has to use other mean | Auxiliary data type | 1 | `AUX_DATA_TYPE_ARBITRARY_HASH=0x00` | | Auxiliary data hash | 32 | | -**Data for AUX_DATA_TYPE_CIP36_REGISTRATION** +**Data for AUX_DATA_TYPE_CVOTE_REGISTRATION** |Field| Length | Comments| |-----|--------|---------| -| Auxiliary data type | 1 | `AUX_DATA_TYPE_CIP36_REGISTRATION=0x01` | +| Auxiliary data type | 1 | `AUX_DATA_TYPE_CVOTE_REGISTRATION=0x01` | This only describes the initial message. All the data for this type of auxiliary data are obtained via a series of additional APDU messages; see [CIP-36 Voting Registration](ins_sign_cip36_registration.md) for the details. diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt index cbe1e9a8..e57620c5 100644 --- a/fuzz/CMakeLists.txt +++ b/fuzz/CMakeLists.txt @@ -96,7 +96,7 @@ set(SOURCES ../src/signTxOutput.c ../src/state.c ../src/signTxPoolRegistration.c - ../src/signTxGovernanceVotingRegistration.c + ../src/signTxCVoteRegistration.c ../src/signTxUtils.c ../src/textUtils.c ../src/txHashBuilder.c diff --git a/src/addressUtilsByron.c b/src/addressUtilsByron.c index bf043a15..c621535c 100644 --- a/src/addressUtilsByron.c +++ b/src/addressUtilsByron.c @@ -86,7 +86,7 @@ size_t cborEncodePubkeyAddressInner( if (protocolMagic == MAINNET_PROTOCOL_MAGIC) { view_appendToken(&out, CBOR_TYPE_MAP, 0 /* addrAttributes is empty */); } else { - /* addrAddtributes contains protocol magic for non-mainnet Byron addresses */ + /* addrAttributes contains protocol magic for non-mainnet Byron addresses */ view_appendToken(&out, CBOR_TYPE_MAP, 1); { view_appendToken(&out, CBOR_TYPE_UNSIGNED, PROTOCOL_MAGIC_ADDRESS_ATTRIBUTE_KEY); /* map key for protocol magic */ diff --git a/src/addressUtilsShelley_test.c b/src/addressUtilsShelley_test.c index 434365a7..9b2b91ba 100644 --- a/src/addressUtilsShelley_test.c +++ b/src/addressUtilsShelley_test.c @@ -126,35 +126,41 @@ static void testAddressDerivation() BASE_PAYMENT_KEY_STAKE_KEY, 0x03, (HD + 1852, HD + 1815, HD + 0, 0, 1), STAKING_KEY_PATH, (HD + 1852, HD + 1815, HD + 0, 2, 0), NO_STAKING_KEY_HASH, "035a53103829a7382c2ab76111fb69f13e69d616824c62058e44f1a8b31d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c" + /* cspell:disable-next-line */ // bech32: addr1qdd9xypc9xnnstp2kas3r7mf7ylxn4sksfxxypvwgnc63vcayfawlf9hwv2fzuygt2km5v92kvf8e3s3mk7ynxw77cwqdquehe ); TESTCASE( BASE_PAYMENT_KEY_STAKE_KEY, 0x00, (HD + 1852, HD + 1815, HD + 0, 0, 1), STAKING_KEY_PATH, (HD + 1852, HD + 1815, HD + 0, 2, 0), NO_STAKING_KEY_HASH, "005a53103829a7382c2ab76111fb69f13e69d616824c62058e44f1a8b31d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c" + /* cspell:disable-next-line */ // bech32: addr1qpd9xypc9xnnstp2kas3r7mf7ylxn4sksfxxypvwgnc63vcayfawlf9hwv2fzuygt2km5v92kvf8e3s3mk7ynxw77cwqhn8sgh ); TESTCASE( BASE_PAYMENT_KEY_STAKE_KEY, 0x00, (HD + 1852, HD + 1815, HD + 0, 0, 1), STAKING_KEY_HASH, NO_STAKING_KEY_PATH, "1d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c", "005a53103829a7382c2ab76111fb69f13e69d616824c62058e44f1a8b31d227aefa4b773149170885aadba30aab3127cc611ddbc4999def61c" + /* cspell:disable-next-line */ // bech32: addr1qpd9xypc9xnnstp2kas3r7mf7ylxn4sksfxxypvwgnc63vcayfawlf9hwv2fzuygt2km5v92kvf8e3s3mk7ynxw77cwqhn8sgh ); TESTCASE( BASE_PAYMENT_KEY_STAKE_KEY, 0x03, (HD + 1852, HD + 1815, HD + 0, 0, 1), STAKING_KEY_HASH, NO_STAKING_KEY_PATH, "122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b4277", "035a53103829a7382c2ab76111fb69f13e69d616824c62058e44f1a8b3122a946b9ad3d2ddf029d3a828f0468aece76895f15c9efbd69b4277" + /* cspell:disable-next-line */ // bech32: addr1qdd9xypc9xnnstp2kas3r7mf7ylxn4sksfxxypvwgnc63vcj922xhxkn6twlq2wn4q50q352annk3903tj00h45mgfmswz93l5 ); TESTCASE( ENTERPRISE_KEY, 0x00, (HD + 1852, HD + 1815, HD + 0, 0, 1), NO_STAKING, NO_STAKING_KEY_PATH, NO_STAKING_KEY_HASH, "605a53103829a7382c2ab76111fb69f13e69d616824c62058e44f1a8b3" + /* cspell:disable-next-line */ // bech32: addr1vpd9xypc9xnnstp2kas3r7mf7ylxn4sksfxxypvwgnc63vc93wyej ); TESTCASE( ENTERPRISE_KEY, 0x03, (HD + 1852, HD + 1815, HD + 0, 0, 1), NO_STAKING, NO_STAKING_KEY_PATH, NO_STAKING_KEY_HASH, "635a53103829a7382c2ab76111fb69f13e69d616824c62058e44f1a8b3" + /* cspell:disable-next-line */ // bech32: addr1vdd9xypc9xnnstp2kas3r7mf7ylxn4sksfxxypvwgnc63vc9wh7em ); @@ -172,16 +178,19 @@ static void testAddressDerivation() TESTCASE_POINTER( POINTER_KEY, 0x00, (HD + 1852, HD + 1815, HD + 0, 0, 1), (1, 2, 3), "405a53103829a7382c2ab76111fb69f13e69d616824c62058e44f1a8b3010203" + /* cspell:disable-next-line */ // bech32: addr1gpd9xypc9xnnstp2kas3r7mf7ylxn4sksfxxypvwgnc63vcpqgpsh506pr ); TESTCASE_POINTER( POINTER_KEY, 0x03, (HD + 1852, HD + 1815, HD + 0, 0, 1), (24157, 177, 42), "435a53103829a7382c2ab76111fb69f13e69d616824c62058e44f1a8b381bc5d81312a" + /* cspell:disable-next-line */ // bech32: addr1gdd9xypc9xnnstp2kas3r7mf7ylxn4sksfxxypvwgnc63vuph3wczvf288aeyu ); TESTCASE_POINTER( POINTER_KEY, 0x03, (HD + 1852, HD + 1815, HD + 0, 0, 1), (0, 0, 0), "435a53103829a7382c2ab76111fb69f13e69d616824c62058e44f1a8b3000000" + /* cspell:disable-next-line */ // bech32: addr1gdd9xypc9xnnstp2kas3r7mf7ylxn4sksfxxypvwgnc63vcqqqqqnnd32q ); diff --git a/src/auxDataHashBuilder.c b/src/auxDataHashBuilder.c index f69220c7..771ca29a 100644 --- a/src/auxDataHashBuilder.c +++ b/src/auxDataHashBuilder.c @@ -18,7 +18,7 @@ enum { HC_AUX_DATA = (1u << 0), // aux data hash context - HC_GOVERNANCE_VOTING_PAYLOAD = (1u << 1) // governance voting registration payload hash context + HC_CVOTE_REGISTRATION_PAYLOAD = (1u << 1) // cip36 registration payload hash context }; /* @@ -31,16 +31,16 @@ The following macros and functions have dual purpose: if (hashContexts & HC_AUX_DATA) { \ blake2b_256_append_cbor_aux_data(&builder->auxDataHash, type, value, true); \ } \ - if (hashContexts & HC_GOVERNANCE_VOTING_PAYLOAD) { \ - blake2b_256_append_cbor_aux_data(&builder->governanceVotingRegistrationData.payloadHash, type, value, false); \ + if (hashContexts & HC_CVOTE_REGISTRATION_PAYLOAD) { \ + blake2b_256_append_cbor_aux_data(&builder->cVoteRegistrationData.payloadHash, type, value, false); \ } #define APPEND_DATA(hashContexts, buffer, bufferSize) \ if (hashContexts & HC_AUX_DATA) { \ blake2b_256_append_buffer_aux_data(&builder->auxDataHash, buffer, bufferSize, true); \ } \ - if (hashContexts & HC_GOVERNANCE_VOTING_PAYLOAD) { \ - blake2b_256_append_buffer_aux_data(&builder->governanceVotingRegistrationData.payloadHash, buffer, bufferSize, false); \ + if (hashContexts & HC_CVOTE_REGISTRATION_PAYLOAD) { \ + blake2b_256_append_buffer_aux_data(&builder->cVoteRegistrationData.payloadHash, buffer, bufferSize, false); \ } @@ -83,7 +83,7 @@ void auxDataHashBuilder_init( { TRACE("Serializing tx auxiliary data"); blake2b_256_init(&builder->auxDataHash); - blake2b_256_init(&builder->governanceVotingRegistrationData.payloadHash); + blake2b_256_init(&builder->cVoteRegistrationData.payloadHash); { APPEND_CBOR(HC_AUX_DATA, CBOR_TYPE_ARRAY, 2); @@ -91,109 +91,109 @@ void auxDataHashBuilder_init( builder->state = AUX_DATA_HASH_BUILDER_INIT; } -void auxDataHashBuilder_governanceVotingRegistration_enter( +void auxDataHashBuilder_cVoteRegistration_enter( aux_data_hash_builder_t* builder, - governance_voting_registration_format_t format + cvote_registration_format_t format ) { _TRACE("state = %d", builder->state); ASSERT(format == CIP15 || format == CIP36); - builder->governanceVotingRegistrationData.format = format; + builder->cVoteRegistrationData.format = format; ASSERT(builder->state == AUX_DATA_HASH_BUILDER_INIT); { - // for governance voting, in the completed auxiliary data + // for cip36 registration, in the completed auxiliary data // there is a map with two entries 61284 and 61285 APPEND_CBOR(HC_AUX_DATA, CBOR_TYPE_MAP, 2); // however, the data being signed is a map with a single entry 61284 - APPEND_CBOR(HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_MAP, 1); + APPEND_CBOR(HC_CVOTE_REGISTRATION_PAYLOAD, CBOR_TYPE_MAP, 1); // the remainder of the payload serialization shares the cbor tokens // with the overall auxiliary data CBOR } - builder->state = AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_REGISTRATION_INIT; + builder->state = AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_INIT; } -void auxDataHashBuilder_governanceVotingRegistration_enterPayload(aux_data_hash_builder_t* builder) +void auxDataHashBuilder_cVoteRegistration_enterPayload(aux_data_hash_builder_t* builder) { _TRACE("state = %d", builder->state); - ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_REGISTRATION_INIT); + ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_INIT); { - // Enter the governance voting key registration payload inner map - size_t mapSize = (builder->governanceVotingRegistrationData.format == CIP36) ? 5 : 4; - APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_UNSIGNED, METADATA_KEY_GOVERNANCE_VOTING_REGISTRATION_PAYLOAD); - APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_MAP, mapSize); + // Enter the cip36 registration payload inner map + size_t mapSize = (builder->cVoteRegistrationData.format == CIP36) ? 5 : 4; + APPEND_CBOR(HC_AUX_DATA | HC_CVOTE_REGISTRATION_PAYLOAD, CBOR_TYPE_UNSIGNED, METADATA_KEY_CVOTE_REGISTRATION_PAYLOAD); + APPEND_CBOR(HC_AUX_DATA | HC_CVOTE_REGISTRATION_PAYLOAD, CBOR_TYPE_MAP, mapSize); } - builder->state = AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_INIT; + builder->state = AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_INIT; } -void auxDataHashBuilder_governanceVotingRegistration_addVotingKey( +void auxDataHashBuilder_cVoteRegistration_addVoteKey( aux_data_hash_builder_t* builder, - const uint8_t* votingPubKeyBuffer, size_t votingPubKeySize + const uint8_t* votePubKeyBuffer, size_t votePubKeySize ) { _TRACE("state = %d", builder->state); - ASSERT(votingPubKeySize < BUFFER_SIZE_PARANOIA); + ASSERT(votePubKeySize < BUFFER_SIZE_PARANOIA); - ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_INIT); + ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_INIT); { - APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_UNSIGNED, GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_KEY_VOTING_KEY); + APPEND_CBOR(HC_AUX_DATA | HC_CVOTE_REGISTRATION_PAYLOAD, CBOR_TYPE_UNSIGNED, CVOTE_REGISTRATION_PAYLOAD_KEY_VOTE_KEY); { - ASSERT(votingPubKeySize == PUBLIC_KEY_SIZE); - APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_BYTES, votingPubKeySize); - APPEND_DATA(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, votingPubKeyBuffer, votingPubKeySize); + ASSERT(votePubKeySize == PUBLIC_KEY_SIZE); + APPEND_CBOR(HC_AUX_DATA | HC_CVOTE_REGISTRATION_PAYLOAD, CBOR_TYPE_BYTES, votePubKeySize); + APPEND_DATA(HC_AUX_DATA | HC_CVOTE_REGISTRATION_PAYLOAD, votePubKeyBuffer, votePubKeySize); } } - builder->state = AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_VOTING_KEY; + builder->state = AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_VOTE_KEY; } -void auxDataHashBuilder_governanceVotingRegistration_enterDelegations( +void auxDataHashBuilder_cVoteRegistration_enterDelegations( aux_data_hash_builder_t* builder, size_t numDelegations ) { _TRACE("state = %d", builder->state); - builder->governanceVotingRegistrationData.remainingDelegations = numDelegations; + builder->cVoteRegistrationData.remainingDelegations = numDelegations; - ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_INIT); + ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_INIT); { - APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_UNSIGNED, GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_KEY_VOTING_KEY); - APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_ARRAY, numDelegations); + APPEND_CBOR(HC_AUX_DATA | HC_CVOTE_REGISTRATION_PAYLOAD, CBOR_TYPE_UNSIGNED, CVOTE_REGISTRATION_PAYLOAD_KEY_VOTE_KEY); + APPEND_CBOR(HC_AUX_DATA | HC_CVOTE_REGISTRATION_PAYLOAD, CBOR_TYPE_ARRAY, numDelegations); } - builder->state = AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_DELEGATIONS; + builder->state = AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_DELEGATIONS; } -void auxDataHashBuilder_governanceVotingRegistration_addDelegation( +void auxDataHashBuilder_cVoteRegistration_addDelegation( aux_data_hash_builder_t* builder, - const uint8_t* votingPubKeyBuffer, size_t votingPubKeySize, + const uint8_t* votePubKeyBuffer, size_t votePubKeySize, uint32_t weight ) { _TRACE("state = %d", builder->state); - ASSERT(votingPubKeySize < BUFFER_SIZE_PARANOIA); + ASSERT(votePubKeySize < BUFFER_SIZE_PARANOIA); - ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_DELEGATIONS); - ASSERT(builder->governanceVotingRegistrationData.remainingDelegations > 0); + ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_DELEGATIONS); + ASSERT(builder->cVoteRegistrationData.remainingDelegations > 0); - builder->governanceVotingRegistrationData.remainingDelegations--; + builder->cVoteRegistrationData.remainingDelegations--; { - APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_ARRAY, 2); + APPEND_CBOR(HC_AUX_DATA | HC_CVOTE_REGISTRATION_PAYLOAD, CBOR_TYPE_ARRAY, 2); { - ASSERT(votingPubKeySize == PUBLIC_KEY_SIZE); - APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_BYTES, votingPubKeySize); - APPEND_DATA(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, votingPubKeyBuffer, votingPubKeySize); + ASSERT(votePubKeySize == PUBLIC_KEY_SIZE); + APPEND_CBOR(HC_AUX_DATA | HC_CVOTE_REGISTRATION_PAYLOAD, CBOR_TYPE_BYTES, votePubKeySize); + APPEND_DATA(HC_AUX_DATA | HC_CVOTE_REGISTRATION_PAYLOAD, votePubKeyBuffer, votePubKeySize); } - APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_UNSIGNED, weight); + APPEND_CBOR(HC_AUX_DATA | HC_CVOTE_REGISTRATION_PAYLOAD, CBOR_TYPE_UNSIGNED, weight); } } -void auxDataHashBuilder_governanceVotingRegistration_addStakingKey( +void auxDataHashBuilder_cVoteRegistration_addStakingKey( aux_data_hash_builder_t* builder, const uint8_t* stakingPubKeyBuffer, size_t stakingPubKeySize ) @@ -204,12 +204,12 @@ void auxDataHashBuilder_governanceVotingRegistration_addStakingKey( switch(builder->state) { - case AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_VOTING_KEY: + case AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_VOTE_KEY: // ok break; - case AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_DELEGATIONS: - ASSERT(builder->governanceVotingRegistrationData.remainingDelegations == 0); + case AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_DELEGATIONS: + ASSERT(builder->cVoteRegistrationData.remainingDelegations == 0); break; default: @@ -218,17 +218,17 @@ void auxDataHashBuilder_governanceVotingRegistration_addStakingKey( } { - APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_UNSIGNED, GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_KEY_STAKING_KEY); + APPEND_CBOR(HC_AUX_DATA | HC_CVOTE_REGISTRATION_PAYLOAD, CBOR_TYPE_UNSIGNED, CVOTE_REGISTRATION_PAYLOAD_KEY_STAKING_KEY); { ASSERT(stakingPubKeySize == PUBLIC_KEY_SIZE); - APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_BYTES, stakingPubKeySize); - APPEND_DATA(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, stakingPubKeyBuffer, stakingPubKeySize); + APPEND_CBOR(HC_AUX_DATA | HC_CVOTE_REGISTRATION_PAYLOAD, CBOR_TYPE_BYTES, stakingPubKeySize); + APPEND_DATA(HC_AUX_DATA | HC_CVOTE_REGISTRATION_PAYLOAD, stakingPubKeyBuffer, stakingPubKeySize); } } - builder->state = AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_STAKING_KEY; + builder->state = AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_STAKING_KEY; } -void auxDataHashBuilder_governanceVotingRegistration_addVotingRewardsAddress( +void auxDataHashBuilder_cVoteRegistration_addPaymentAddress( aux_data_hash_builder_t* builder, const uint8_t* addressBuffer, size_t addressSize ) @@ -238,65 +238,65 @@ void auxDataHashBuilder_governanceVotingRegistration_addVotingRewardsAddress( ASSERT(addressSize > 0); ASSERT(addressSize < BUFFER_SIZE_PARANOIA); - ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_STAKING_KEY); + ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_STAKING_KEY); { - APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_UNSIGNED, GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_KEY_VOTING_REWARDS_ADDRESS); + APPEND_CBOR(HC_AUX_DATA | HC_CVOTE_REGISTRATION_PAYLOAD, CBOR_TYPE_UNSIGNED, CVOTE_REGISTRATION_PAYLOAD_PAYMENT_ADDRESS); { - APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_BYTES, addressSize); - APPEND_DATA(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, addressBuffer, addressSize); + APPEND_CBOR(HC_AUX_DATA | HC_CVOTE_REGISTRATION_PAYLOAD, CBOR_TYPE_BYTES, addressSize); + APPEND_DATA(HC_AUX_DATA | HC_CVOTE_REGISTRATION_PAYLOAD, addressBuffer, addressSize); } } - builder->state = AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_VOTING_REWARDS_ADDRESS; + builder->state = AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_PAYMENT_ADDRESS; } -void auxDataHashBuilder_governanceVotingRegistration_addNonce( +void auxDataHashBuilder_cVoteRegistration_addNonce( aux_data_hash_builder_t* builder, uint64_t nonce ) { _TRACE("state = %d", builder->state); - ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_VOTING_REWARDS_ADDRESS); + ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_PAYMENT_ADDRESS); { - APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_UNSIGNED, GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_KEY_NONCE); - APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_UNSIGNED, nonce); + APPEND_CBOR(HC_AUX_DATA | HC_CVOTE_REGISTRATION_PAYLOAD, CBOR_TYPE_UNSIGNED, CVOTE_REGISTRATION_PAYLOAD_KEY_NONCE); + APPEND_CBOR(HC_AUX_DATA | HC_CVOTE_REGISTRATION_PAYLOAD, CBOR_TYPE_UNSIGNED, nonce); } - builder->state = AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_NONCE; + builder->state = AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_NONCE; } -void auxDataHashBuilder_governanceVotingRegistration_addVotingPurpose( +void auxDataHashBuilder_cVoteRegistration_addVotingPurpose( aux_data_hash_builder_t* builder, uint64_t votingPurpose ) { _TRACE("state = %d", builder->state); - ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_NONCE); + ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_NONCE); { - APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_UNSIGNED, GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_KEY_VOTING_PURPOSE); - APPEND_CBOR(HC_AUX_DATA | HC_GOVERNANCE_VOTING_PAYLOAD, CBOR_TYPE_UNSIGNED, votingPurpose); + APPEND_CBOR(HC_AUX_DATA | HC_CVOTE_REGISTRATION_PAYLOAD, CBOR_TYPE_UNSIGNED, CVOTE_REGISTRATION_PAYLOAD_VOTING_PURPOSE); + APPEND_CBOR(HC_AUX_DATA | HC_CVOTE_REGISTRATION_PAYLOAD, CBOR_TYPE_UNSIGNED, votingPurpose); } - builder->state = AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_VOTING_PURPOSE; + builder->state = AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_VOTING_PURPOSE; } -void auxDataHashBuilder_governanceVotingRegistration_finalizePayload(aux_data_hash_builder_t* builder, uint8_t* outBuffer, size_t outSize) +void auxDataHashBuilder_cVoteRegistration_finalizePayload(aux_data_hash_builder_t* builder, uint8_t* outBuffer, size_t outSize) { _TRACE("state = %d", builder->state); ASSERT(outSize < BUFFER_SIZE_PARANOIA); ASSERT( - builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_NONCE || - builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_VOTING_PURPOSE + builder->state == AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_NONCE || + builder->state == AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_VOTING_PURPOSE ); - ASSERT(outSize == GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_HASH_LENGTH); + ASSERT(outSize == CVOTE_REGISTRATION_PAYLOAD_HASH_LENGTH); { - blake2b_256_finalize(&builder->governanceVotingRegistrationData.payloadHash, outBuffer, outSize); + blake2b_256_finalize(&builder->cVoteRegistrationData.payloadHash, outBuffer, outSize); } } -void auxDataHashBuilder_governanceVotingRegistration_addSignature( +void auxDataHashBuilder_cVoteRegistration_addSignature( aux_data_hash_builder_t* builder, const uint8_t* signatureBuffer, size_t signatureSize ) @@ -306,29 +306,29 @@ void auxDataHashBuilder_governanceVotingRegistration_addSignature( ASSERT(signatureSize < BUFFER_SIZE_PARANOIA); ASSERT( - builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_NONCE || - builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_VOTING_PURPOSE + builder->state == AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_NONCE || + builder->state == AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_VOTING_PURPOSE ); { - APPEND_CBOR(HC_AUX_DATA, CBOR_TYPE_UNSIGNED, METADATA_KEY_GOVERNANCE_VOTING_SIGNATURE); + APPEND_CBOR(HC_AUX_DATA, CBOR_TYPE_UNSIGNED, METADATA_KEY_CVOTE_REGISTRATION_SIGNATURE); { ASSERT(signatureSize == ED25519_SIGNATURE_LENGTH); APPEND_CBOR(HC_AUX_DATA, CBOR_TYPE_MAP, 1); - APPEND_CBOR(HC_AUX_DATA, CBOR_TYPE_UNSIGNED, GOVERNANCE_VOTING_REGISTRATION_SIGNATURE_KEY); + APPEND_CBOR(HC_AUX_DATA, CBOR_TYPE_UNSIGNED, CVOTE_REGISTRATION_SIGNATURE_KEY); APPEND_CBOR(HC_AUX_DATA, CBOR_TYPE_BYTES, signatureSize); APPEND_DATA(HC_AUX_DATA, signatureBuffer, signatureSize); } } - builder->state = AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_SIGNATURE; + builder->state = AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_SIGNATURE; } -void auxDataHashBuilder_governanceVotingRegistration_addAuxiliaryScripts( +void auxDataHashBuilder_cVoteRegistration_addAuxiliaryScripts( aux_data_hash_builder_t* builder ) { _TRACE("state = %d", builder->state); - ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_SIGNATURE); + ASSERT(builder->state == AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_SIGNATURE); { // auxiliary scripts currently hard-coded to an empty list APPEND_CBOR(HC_AUX_DATA, CBOR_TYPE_ARRAY, 0); diff --git a/src/auxDataHashBuilder.h b/src/auxDataHashBuilder.h index c2488384..0dd78ffc 100644 --- a/src/auxDataHashBuilder.h +++ b/src/auxDataHashBuilder.h @@ -6,33 +6,33 @@ #include "keyDerivation.h" enum { - METADATA_KEY_GOVERNANCE_VOTING_REGISTRATION_PAYLOAD = 61284, - METADATA_KEY_GOVERNANCE_VOTING_SIGNATURE = 61285, + METADATA_KEY_CVOTE_REGISTRATION_PAYLOAD = 61284, + METADATA_KEY_CVOTE_REGISTRATION_SIGNATURE = 61285, }; enum { - GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_KEY_VOTING_KEY = 1, - GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_KEY_STAKING_KEY = 2, - GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_KEY_VOTING_REWARDS_ADDRESS = 3, - GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_KEY_NONCE = 4, - GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_KEY_VOTING_PURPOSE = 5, + CVOTE_REGISTRATION_PAYLOAD_KEY_VOTE_KEY = 1, + CVOTE_REGISTRATION_PAYLOAD_KEY_STAKING_KEY = 2, + CVOTE_REGISTRATION_PAYLOAD_PAYMENT_ADDRESS = 3, + CVOTE_REGISTRATION_PAYLOAD_KEY_NONCE = 4, + CVOTE_REGISTRATION_PAYLOAD_VOTING_PURPOSE = 5, }; enum { - GOVERNANCE_VOTING_REGISTRATION_SIGNATURE_KEY = 1, + CVOTE_REGISTRATION_SIGNATURE_KEY = 1, }; typedef enum { AUX_DATA_HASH_BUILDER_INIT = 100, - AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_REGISTRATION_INIT = 200, - AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_INIT = 210, - AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_VOTING_KEY = 211, - AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_DELEGATIONS = 212, - AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_STAKING_KEY = 213, - AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_VOTING_REWARDS_ADDRESS = 214, - AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_NONCE = 215, - AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_PAYLOAD_VOTING_PURPOSE = 216, - AUX_DATA_HASH_BUILDER_IN_GOVERNANCE_VOTING_SIGNATURE = 220, + AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_INIT = 200, + AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_INIT = 210, + AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_VOTE_KEY = 211, + AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_DELEGATIONS = 212, + AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_STAKING_KEY = 213, + AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_PAYMENT_ADDRESS = 214, + AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_NONCE = 215, + AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_PAYLOAD_VOTING_PURPOSE = 216, + AUX_DATA_HASH_BUILDER_IN_CVOTE_REGISTRATION_SIGNATURE = 220, AUX_DATA_HASH_BUILDER_IN_AUXILIARY_SCRIPTS = 300, AUX_DATA_HASH_BUILDER_FINISHED = 400, } aux_data_hash_builder_state_t; @@ -40,14 +40,14 @@ typedef enum { typedef enum { CIP15 = 1, CIP36 = 2 -} governance_voting_registration_format_t; +} cvote_registration_format_t; typedef struct { struct { blake2b_256_context_t payloadHash; - governance_voting_registration_format_t format; + cvote_registration_format_t format; uint16_t remainingDelegations; - } governanceVotingRegistrationData; + } cVoteRegistrationData; aux_data_hash_builder_state_t state; blake2b_256_context_t auxDataHash; @@ -58,48 +58,48 @@ void auxDataHashBuilder_init( aux_data_hash_builder_t* builder ); -void auxDataHashBuilder_governanceVotingRegistration_enter( +void auxDataHashBuilder_cVoteRegistration_enter( aux_data_hash_builder_t* builder, - governance_voting_registration_format_t format + cvote_registration_format_t format ); -void auxDataHashBuilder_governanceVotingRegistration_enterPayload(aux_data_hash_builder_t* builder); -void auxDataHashBuilder_governanceVotingRegistration_addVotingKey( +void auxDataHashBuilder_cVoteRegistration_enterPayload(aux_data_hash_builder_t* builder); +void auxDataHashBuilder_cVoteRegistration_addVoteKey( aux_data_hash_builder_t* builder, - const uint8_t* votingPubKeyBuffer, size_t votingPubKeySize + const uint8_t* votePubKeyBuffer, size_t votePubKeySize ); -void auxDataHashBuilder_governanceVotingRegistration_enterDelegations( +void auxDataHashBuilder_cVoteRegistration_enterDelegations( aux_data_hash_builder_t* builder, size_t numDelegations ); -void auxDataHashBuilder_governanceVotingRegistration_addDelegation( +void auxDataHashBuilder_cVoteRegistration_addDelegation( aux_data_hash_builder_t* builder, - const uint8_t* votingPubKeyBuffer, size_t votingPubKeySize, + const uint8_t* votePubKeyBuffer, size_t votePubKeySize, uint32_t weight ); -void auxDataHashBuilder_governanceVotingRegistration_addStakingKey( +void auxDataHashBuilder_cVoteRegistration_addStakingKey( aux_data_hash_builder_t* builder, const uint8_t* stakingPubKeyBuffer, size_t stakingPubKeySize ); -void auxDataHashBuilder_governanceVotingRegistration_addVotingRewardsAddress( +void auxDataHashBuilder_cVoteRegistration_addPaymentAddress( aux_data_hash_builder_t* builder, const uint8_t* addressBuffer, size_t addressSize ); -void auxDataHashBuilder_governanceVotingRegistration_addNonce(aux_data_hash_builder_t* builder, uint64_t nonce); -void auxDataHashBuilder_governanceVotingRegistration_addVotingPurpose( +void auxDataHashBuilder_cVoteRegistration_addNonce(aux_data_hash_builder_t* builder, uint64_t nonce); +void auxDataHashBuilder_cVoteRegistration_addVotingPurpose( aux_data_hash_builder_t* builder, uint64_t votingPurpose ); -void auxDataHashBuilder_governanceVotingRegistration_finalizePayload( +void auxDataHashBuilder_cVoteRegistration_finalizePayload( aux_data_hash_builder_t* builder, uint8_t* outBuffer, size_t outSize ); -void auxDataHashBuilder_governanceVotingRegistration_addSignature( +void auxDataHashBuilder_cVoteRegistration_addSignature( aux_data_hash_builder_t* builder, const uint8_t* signatureBuffer, size_t signatureSize ); -void auxDataHashBuilder_governanceVotingRegistration_addAuxiliaryScripts(aux_data_hash_builder_t* builder); +void auxDataHashBuilder_cVoteRegistration_addAuxiliaryScripts(aux_data_hash_builder_t* builder); void auxDataHashBuilder_finalize( aux_data_hash_builder_t* builder, diff --git a/src/auxDataHashBuilder_test.c b/src/auxDataHashBuilder_test.c index 45e4b176..2513a64d 100644 --- a/src/auxDataHashBuilder_test.c +++ b/src/auxDataHashBuilder_test.c @@ -8,28 +8,28 @@ void test_CIP15() { - PRINTF("governance voting CIP15\n"); + PRINTF("CIP15 voting registration\n"); - static const char* votingKey = "3B40265111D8BB3C3C608D95B3A0BF83461ACE32D79336579A1939B3AAD1C0B7"; + static const char* voteKey = "3B40265111D8BB3C3C608D95B3A0BF83461ACE32D79336579A1939B3AAD1C0B7"; static const char* stakingKey = "BC65BE1B0B9D7531778A1317C2AA6DE936963C3F9AC7D5EE9E9EDA25E0C97C5E"; - static const char* votingRewardsAddress = "0180F9E2C88E6C817008F3A812ED889B4A4DA8E0BD103F86E7335422AA122A946B9AD3D2DDF029D3A828F0468AECE76895F15C9EFBD69B4277"; + static const char* paymentAddress = "0180F9E2C88E6C817008F3A812ED889B4A4DA8E0BD103F86E7335422AA122A946B9AD3D2DDF029D3A828F0468AECE76895F15C9EFBD69B4277"; static uint64_t nonce = 22634813; - static const char* governanceVotingRegistrationSignature = "0EA4A424522DD485F16466CD5A754F3C8DBD4D1976C912624E3465C540B1D0776C92633FC64BE057F947AAC561012FE55ACD3C54EF7BECE0DA0B90CF02DC760D"; + static const char* cVoteRegistrationSignature = "0EA4A424522DD485F16466CD5A754F3C8DBD4D1976C912624E3465C540B1D0776C92633FC64BE057F947AAC561012FE55ACD3C54EF7BECE0DA0B90CF02DC760D"; - static const char* expectedGovernanceVotingRegistrationPayloadHashHex = "2EEA6A5168066BDA411F80BE10B50646378616C3414C711A61D363C7879B5CBC"; + static const char* expectedCVoteRegistrationPayloadHashHex = "2EEA6A5168066BDA411F80BE10B50646378616C3414C711A61D363C7879B5CBC"; static const char* expectedAuxDataHashHex = "07cdec3a795626019739f275582433eabe32da80f82aeb74e4916b547c01a589"; aux_data_hash_builder_t builder; auxDataHashBuilder_init(&builder); - auxDataHashBuilder_governanceVotingRegistration_enter(&builder, CIP15); - auxDataHashBuilder_governanceVotingRegistration_enterPayload(&builder); + auxDataHashBuilder_cVoteRegistration_enter(&builder, CIP15); + auxDataHashBuilder_cVoteRegistration_enterPayload(&builder); { uint8_t tmp[32] = {0}; - size_t tmpSize = decode_hex(votingKey, tmp, SIZEOF(tmp)); - auxDataHashBuilder_governanceVotingRegistration_addVotingKey( + size_t tmpSize = decode_hex(voteKey, tmp, SIZEOF(tmp)); + auxDataHashBuilder_cVoteRegistration_addVoteKey( &builder, tmp, tmpSize ); @@ -38,7 +38,7 @@ void test_CIP15() { uint8_t tmp[32] = {0}; size_t tmpSize = decode_hex(stakingKey, tmp, SIZEOF(tmp)); - auxDataHashBuilder_governanceVotingRegistration_addStakingKey( + auxDataHashBuilder_cVoteRegistration_addStakingKey( &builder, tmp, tmpSize ); @@ -46,23 +46,23 @@ void test_CIP15() { uint8_t tmp[57] = {0}; - size_t tmpSize = decode_hex(votingRewardsAddress, tmp, SIZEOF(tmp)); - auxDataHashBuilder_governanceVotingRegistration_addVotingRewardsAddress( + size_t tmpSize = decode_hex(paymentAddress, tmp, SIZEOF(tmp)); + auxDataHashBuilder_cVoteRegistration_addPaymentAddress( &builder, tmp, tmpSize ); } - auxDataHashBuilder_governanceVotingRegistration_addNonce(&builder, nonce); + auxDataHashBuilder_cVoteRegistration_addNonce(&builder, nonce); { uint8_t result[AUX_DATA_HASH_LENGTH] = {0}; - auxDataHashBuilder_governanceVotingRegistration_finalizePayload(&builder, result, SIZEOF(result)); + auxDataHashBuilder_cVoteRegistration_finalizePayload(&builder, result, SIZEOF(result)); uint8_t expected[AUX_DATA_HASH_LENGTH] = {0}; - decode_hex(expectedGovernanceVotingRegistrationPayloadHashHex, expected, SIZEOF(expected)); + decode_hex(expectedCVoteRegistrationPayloadHashHex, expected, SIZEOF(expected)); - PRINTF("Governance voting registration payload hash hex\n"); + PRINTF("registration payload hash hex\n"); PRINTF("%.*h\n", 32, result); EXPECT_EQ_BYTES(result, expected, 32); @@ -70,14 +70,14 @@ void test_CIP15() { uint8_t tmp[64] = {0}; - size_t tmpSize = decode_hex(governanceVotingRegistrationSignature, tmp, SIZEOF(tmp)); - auxDataHashBuilder_governanceVotingRegistration_addSignature( + size_t tmpSize = decode_hex(cVoteRegistrationSignature, tmp, SIZEOF(tmp)); + auxDataHashBuilder_cVoteRegistration_addSignature( &builder, tmp, tmpSize ); } - auxDataHashBuilder_governanceVotingRegistration_addAuxiliaryScripts(&builder); + auxDataHashBuilder_cVoteRegistration_addAuxiliaryScripts(&builder); { uint8_t result[AUX_DATA_HASH_LENGTH] = {0}; @@ -95,7 +95,7 @@ void test_CIP15() void test_CIP36() { - PRINTF("governance voting CIP36\n"); + PRINTF("CIP36 voting registration\n"); // data from https://cips.cardano.org/cips/cip36/test-vector.md.html @@ -105,26 +105,26 @@ void test_CIP36() static const uint64_t delegationWeight2 = 3; static const char* stakingKey = "86870efc99c453a873a16492ce87738ec79a0ebd064379a62e2c9cf4e119219e"; - static const char* votingRewardsAddress = "e0ae3a0a7aeda4aea522e74e4fe36759fca80789a613a58a4364f6ecef"; + static const char* paymentAddress = "e0ae3a0a7aeda4aea522e74e4fe36759fca80789a613a58a4364f6ecef"; static const uint64_t nonce = 1234; static const uint64_t votingPurpose = 0; - static const char* governanceVotingRegistrationSignature = "0ea4a424522dd485f16466cd5a754f3c8dbd4d1976c912624e3465c540b1d0776c92633fc64be057f947aac561012fe55acd3c54ef7bece0da0b90cf02dc760d"; + static const char* cVoteRegistrationSignature = "0ea4a424522dd485f16466cd5a754f3c8dbd4d1976c912624e3465c540b1d0776c92633fc64be057f947aac561012fe55acd3c54ef7bece0da0b90cf02dc760d"; - static const char* expectedGovernanceVotingRegistrationPayloadHashHex = "5bc0681f173efd76e1989037a3694b8a7abea22053f5940cbb5cfcdf721007d7"; + static const char* expectedCVoteRegistrationPayloadHashHex = "5bc0681f173efd76e1989037a3694b8a7abea22053f5940cbb5cfcdf721007d7"; static const char* expectedAuxDataHashHex = "3786b3ad677129e43dbb3456e45e5af589e9aae81062ef7e26f15fde00df421d"; aux_data_hash_builder_t builder; auxDataHashBuilder_init(&builder); - auxDataHashBuilder_governanceVotingRegistration_enter(&builder, CIP36); - auxDataHashBuilder_governanceVotingRegistration_enterPayload(&builder); + auxDataHashBuilder_cVoteRegistration_enter(&builder, CIP36); + auxDataHashBuilder_cVoteRegistration_enterPayload(&builder); - auxDataHashBuilder_governanceVotingRegistration_enterDelegations(&builder, 2); + auxDataHashBuilder_cVoteRegistration_enterDelegations(&builder, 2); { uint8_t tmp[32] = {0}; size_t tmpSize = decode_hex(delegationKey1, tmp, SIZEOF(tmp)); - auxDataHashBuilder_governanceVotingRegistration_addDelegation( + auxDataHashBuilder_cVoteRegistration_addDelegation( &builder, tmp, tmpSize, delegationWeight1 @@ -133,7 +133,7 @@ void test_CIP36() { uint8_t tmp[32] = {0}; size_t tmpSize = decode_hex(delegationKey2, tmp, SIZEOF(tmp)); - auxDataHashBuilder_governanceVotingRegistration_addDelegation( + auxDataHashBuilder_cVoteRegistration_addDelegation( &builder, tmp, tmpSize, delegationWeight2 @@ -143,7 +143,7 @@ void test_CIP36() { uint8_t tmp[32] = {0}; size_t tmpSize = decode_hex(stakingKey, tmp, SIZEOF(tmp)); - auxDataHashBuilder_governanceVotingRegistration_addStakingKey( + auxDataHashBuilder_cVoteRegistration_addStakingKey( &builder, tmp, tmpSize ); @@ -151,24 +151,24 @@ void test_CIP36() { uint8_t tmp[57] = {0}; - size_t tmpSize = decode_hex(votingRewardsAddress, tmp, SIZEOF(tmp)); - auxDataHashBuilder_governanceVotingRegistration_addVotingRewardsAddress( + size_t tmpSize = decode_hex(paymentAddress, tmp, SIZEOF(tmp)); + auxDataHashBuilder_cVoteRegistration_addPaymentAddress( &builder, tmp, tmpSize ); } - auxDataHashBuilder_governanceVotingRegistration_addNonce(&builder, nonce); - auxDataHashBuilder_governanceVotingRegistration_addVotingPurpose(&builder, votingPurpose); + auxDataHashBuilder_cVoteRegistration_addNonce(&builder, nonce); + auxDataHashBuilder_cVoteRegistration_addVotingPurpose(&builder, votingPurpose); { uint8_t result[AUX_DATA_HASH_LENGTH] = {0}; - auxDataHashBuilder_governanceVotingRegistration_finalizePayload(&builder, result, SIZEOF(result)); + auxDataHashBuilder_cVoteRegistration_finalizePayload(&builder, result, SIZEOF(result)); uint8_t expected[AUX_DATA_HASH_LENGTH] = {0}; - decode_hex(expectedGovernanceVotingRegistrationPayloadHashHex, expected, SIZEOF(expected)); + decode_hex(expectedCVoteRegistrationPayloadHashHex, expected, SIZEOF(expected)); - PRINTF("Governance voting registration payload hash hex\n"); + PRINTF("registration payload hash hex\n"); PRINTF("%.*h\n", 32, result); EXPECT_EQ_BYTES(result, expected, 32); @@ -176,14 +176,14 @@ void test_CIP36() { uint8_t tmp[64] = {0}; - size_t tmpSize = decode_hex(governanceVotingRegistrationSignature, tmp, SIZEOF(tmp)); - auxDataHashBuilder_governanceVotingRegistration_addSignature( + size_t tmpSize = decode_hex(cVoteRegistrationSignature, tmp, SIZEOF(tmp)); + auxDataHashBuilder_cVoteRegistration_addSignature( &builder, tmp, tmpSize ); } - auxDataHashBuilder_governanceVotingRegistration_addAuxiliaryScripts(&builder); + auxDataHashBuilder_cVoteRegistration_addAuxiliaryScripts(&builder); { uint8_t result[AUX_DATA_HASH_LENGTH] = {0}; diff --git a/src/base58.c b/src/base58.c index cc478f6c..59853102 100644 --- a/src/base58.c +++ b/src/base58.c @@ -22,6 +22,7 @@ #define MAX_BUFFER_SIZE 124 +/* cspell:disable-next-line */ static const char BASE58ALPHABET[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; size_t base58_encode( diff --git a/src/base58_test.c b/src/base58_test.c index be5e39fd..522c85b1 100644 --- a/src/base58_test.c +++ b/src/base58_test.c @@ -36,6 +36,7 @@ void run_base58_test() { "82d818582183581ce63175c654dfd93a9290342a067158dc0f57a1108ddbd8cace3839bda0001a0a0e41ce", + /* cspell:disable-next-line */ "Ae2tdPwUPEZKmwoy3AU3cXb5Chnasj6mvVNxV1H11997q3VW5ihbSfQwGpm" }, diff --git a/src/bech32.c b/src/bech32.c index 5fe07aba..4ac6a7f3 100644 --- a/src/bech32.c +++ b/src/bech32.c @@ -32,6 +32,7 @@ uint32_t bech32_polymod_step(uint32_t pre) (-((b >> 3) & 1) & 0x3d4233ddUL) ^ (-((b >> 4) & 1) & 0x2a1462b3UL); } +/* cspell:disable-next-line */ static const char* charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; /** Encode a Bech32 string diff --git a/src/bech32_test.c b/src/bech32_test.c index 9c900a99..66dfaef6 100644 --- a/src/bech32_test.c +++ b/src/bech32_test.c @@ -36,12 +36,14 @@ void run_bech32_test() const char* inputBytesHex; const char* expectedHex; } testVectors[] = { + /* cspell:disable */ {"a", "", "a12uel5l"}, {"an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio", "", "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs"}, {"abcdef", "00443214c74254b635cf84653a56d7c675be77df", "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw"}, {"1", "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j"}, {"split", "c5f38b70305f519bf66d85fb6cf03058f3dde463ecd7918f2dc743918f2d", "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w"}, {"addr", "009493315cd92eb5d8c4304e67b7e16ae36d61d34502694657811a2c8e32c728d3861e164cab28cb8f006448139c8f1740ffb8e7aa9e5232dc", "addr1qz2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3jcu5d8ps7zex2k2xt3uqxgjqnnj83ws8lhrn648jjxtwqcyl47r"} + /* cspell:enable */ }; ITERATE(it, testVectors) { testcase_bech32(PTR_PIC(it->hrp), PTR_PIC(it->inputBytesHex), PTR_PIC(it->expectedHex)); diff --git a/src/bip44.c b/src/bip44.c index 759ae448..0907eb14 100644 --- a/src/bip44.c +++ b/src/bip44.c @@ -119,11 +119,11 @@ bool bip44_hasPoolColdKeyPrefix(const bip44_path_t* pathSpec) } // /1694'/1815' -bool bip44_hasGovernanceVotingKeyPrefix(const bip44_path_t* pathSpec) +bool bip44_hasCVoteKeyPrefix(const bip44_path_t* pathSpec) { #define CHECK(cond) if (!(cond)) return false CHECK(pathSpec->length > BIP44_I_COIN_TYPE); - CHECK(pathSpec->path[BIP44_I_PURPOSE] == harden(PURPOSE_GOVERNANCE_VOTING_KEY)); + CHECK(pathSpec->path[BIP44_I_PURPOSE] == harden(PURPOSE_CVOTE_KEY)); CHECK(pathSpec->path[BIP44_I_COIN_TYPE] == harden(ADA_COIN_TYPE)); return true; #undef CHECK @@ -267,11 +267,11 @@ bool bip44_isPoolColdKeyPath(const bip44_path_t* pathSpec) #undef CHECK } -bool bip44_isGovernanceVotingKeyPath(const bip44_path_t* pathSpec) +bool bip44_isCVoteKeyPath(const bip44_path_t* pathSpec) { #define CHECK(cond) if (!(cond)) return false CHECK(pathSpec->length == BIP44_I_ADDRESS + 1); - CHECK(bip44_hasGovernanceVotingKeyPrefix(pathSpec)); + CHECK(bip44_hasCVoteKeyPrefix(pathSpec)); CHECK(bip44_getAccount(pathSpec) >= HARDENED_BIP32); CHECK(pathSpec->path[BIP44_I_CHAIN] == 0); // in the future, more might be allowed CHECK(!isHardened(bip44_getAddressValue(pathSpec))); @@ -411,9 +411,9 @@ static bip44_path_type_t bip44_classifyMultisigWalletPath(const bip44_path_t* pa } } -static bip44_path_type_t bip44_classifyGovernanceVotingPath(const bip44_path_t* pathSpec) +static bip44_path_type_t bip44_classifyCVotePath(const bip44_path_t* pathSpec) { - ASSERT(bip44_hasGovernanceVotingKeyPrefix(pathSpec)); + ASSERT(bip44_hasCVoteKeyPrefix(pathSpec)); // account must be hardened if (!bip44_containsAccount(pathSpec)) { @@ -425,11 +425,11 @@ static bip44_path_type_t bip44_classifyGovernanceVotingPath(const bip44_path_t* switch (pathSpec->length) { case 3: { - return PATH_GOVERNANCE_VOTING_ACCOUNT; + return PATH_CVOTE_ACCOUNT; } case 5: { - return bip44_isGovernanceVotingKeyPath(pathSpec) ? - PATH_GOVERNANCE_VOTING_KEY : + return bip44_isCVoteKeyPath(pathSpec) ? + PATH_CVOTE_KEY : PATH_INVALID; } default: @@ -463,8 +463,8 @@ bip44_path_type_t bip44_classifyPath(const bip44_path_t* pathSpec) } } - if (bip44_hasGovernanceVotingKeyPrefix(pathSpec)) { - return bip44_classifyGovernanceVotingPath(pathSpec); + if (bip44_hasCVoteKeyPrefix(pathSpec)) { + return bip44_classifyCVotePath(pathSpec); } return PATH_INVALID; @@ -494,10 +494,10 @@ bool bip44_isPathReasonable(const bip44_path_t* pathSpec) case PATH_POOL_COLD_KEY: return bip44_hasReasonablePoolColdKeyIndex(pathSpec); - case PATH_GOVERNANCE_VOTING_ACCOUNT: + case PATH_CVOTE_ACCOUNT: return bip44_hasReasonableAccount(pathSpec); - case PATH_GOVERNANCE_VOTING_KEY: + case PATH_CVOTE_KEY: return bip44_hasReasonableAccount(pathSpec) && bip44_hasReasonableAddress(pathSpec); default: diff --git a/src/bip44.h b/src/bip44.h index f1e79849..75b882e4 100644 --- a/src/bip44.h +++ b/src/bip44.h @@ -22,7 +22,7 @@ static const uint32_t PURPOSE_MINT = 1855; static const uint32_t PURPOSE_POOL_COLD_KEY = 1853; -static const uint32_t PURPOSE_GOVERNANCE_VOTING_KEY = 1694; +static const uint32_t PURPOSE_CVOTE_KEY = 1694; static const uint32_t ADA_COIN_TYPE = 1815; @@ -42,7 +42,7 @@ enum { // wallet keys: // ordinary https://cips.cardano.org/cips/cip1852/ // multisig https://cips.cardano.org/cips/cip1854/ - // governance voting keys: + // cip36 vote keys: // https://cips.cardano.org/cips/cip36/ BIP44_I_PURPOSE = 0, BIP44_I_COIN_TYPE = 1, @@ -66,7 +66,7 @@ bool bip44_hasOrdinaryWalletKeyPrefix(const bip44_path_t* pathSpec); bool bip44_hasMultisigWalletKeyPrefix(const bip44_path_t* pathSpec); bool bip44_hasMintKeyPrefix(const bip44_path_t* pathSpec); bool bip44_hasPoolColdKeyPrefix(const bip44_path_t* pathSpec); -bool bip44_hasGovernanceVotingKeyPrefix(const bip44_path_t* pathSpec); +bool bip44_hasCVoteKeyPrefix(const bip44_path_t* pathSpec); bool bip44_containsAccount(const bip44_path_t* pathSpec); uint32_t bip44_getAccount(const bip44_path_t* pathSpec); @@ -82,7 +82,7 @@ bool bip44_isMintKeyPath(const bip44_path_t* pathSpec); bool bip44_isPoolColdKeyPath(const bip44_path_t* pathSpec); -bool bip44_isGovernanceVotingKeyPath(const bip44_path_t* pathSpec); +bool bip44_isCVoteKeyPath(const bip44_path_t* pathSpec); size_t bip44_printToStr(const bip44_path_t*, char* out, size_t outSize); @@ -96,7 +96,7 @@ typedef enum { PATH_ORDINARY_SPENDING_KEY, PATH_MULTISIG_SPENDING_KEY, - // hd wallet reward adress, withdrawal witness, pool owner + // hd wallet reward address, withdrawal witness, pool owner PATH_ORDINARY_STAKING_KEY, PATH_MULTISIG_STAKING_KEY, @@ -106,9 +106,9 @@ typedef enum { // pool cold key in pool registrations and retirements PATH_POOL_COLD_KEY, - // governance voting, incl. Catalyst - PATH_GOVERNANCE_VOTING_ACCOUNT, - PATH_GOVERNANCE_VOTING_KEY, + // cip36 voting, incl. Catalyst + PATH_CVOTE_ACCOUNT, + PATH_CVOTE_KEY, // none of the above PATH_INVALID, diff --git a/src/cardano.h b/src/cardano.h index 84fbd46b..cf79bccb 100644 --- a/src/cardano.h +++ b/src/cardano.h @@ -19,7 +19,7 @@ STATIC_ASSERT(LOVELACE_MAX_SUPPLY < LOVELACE_INVALID, "bad LOVELACE_INVALID"); #define TX_HASH_LENGTH 32 #define AUX_DATA_HASH_LENGTH 32 #define POOL_METADATA_HASH_LENGTH 32 -#define GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_HASH_LENGTH 32 +#define CVOTE_REGISTRATION_PAYLOAD_HASH_LENGTH 32 #define ED25519_SIGNATURE_LENGTH 64 #define SCRIPT_HASH_LENGTH 28 #define SCRIPT_DATA_HASH_LENGTH 32 diff --git a/src/errors.h b/src/errors.h index 68ecc4f0..578cf6ee 100644 --- a/src/errors.h +++ b/src/errors.h @@ -2,7 +2,7 @@ #define H_CARDANO_APP_ERRORS enum { - // Successfull responses + // Successful responses SUCCESS = 0x9000, // Start of error which trigger automatic response diff --git a/src/handlers.c b/src/handlers.c index 07204b1a..4c6cc5a1 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -13,7 +13,7 @@ #include "deriveNativeScriptHash.h" #include "signTx.h" #include "signOpCert.h" -#include "signGovernanceVote.h" +#include "signCVote.h" // The APDU protocol uses a single-byte instruction code (INS) to specify // which command should be executed. We'll use this code to dispatch on a @@ -34,7 +34,7 @@ handler_fn_t* lookupHandler(uint8_t ins) // 0x2* - signing related CASE(0x21, signTx_handleAPDU); CASE(0x22, signOpCert_handleAPDU); - CASE(0x23, signGovernanceVote_handleAPDU); + CASE(0x23, signCVote_handleAPDU); #ifdef DEVEL // 0xF* - debug_mode related diff --git a/src/messageSigning.c b/src/messageSigning.c index 5e463eb6..a6aab51f 100644 --- a/src/messageSigning.c +++ b/src/messageSigning.c @@ -76,11 +76,11 @@ void getWitness(bip44_path_t* pathSpec, #endif } -void getGovernanceVotingRegistrationSignature(bip44_path_t* pathSpec, - const uint8_t* payloadHashBuffer, size_t payloadHashSize, - uint8_t* outBuffer, size_t outSize) +void getCVoteRegistrationSignature(bip44_path_t* pathSpec, + const uint8_t* payloadHashBuffer, size_t payloadHashSize, + uint8_t* outBuffer, size_t outSize) { - ASSERT(payloadHashSize == GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_HASH_LENGTH); + ASSERT(payloadHashSize == CVOTE_REGISTRATION_PAYLOAD_HASH_LENGTH); ASSERT(outSize < BUFFER_SIZE_PARANOIA); #ifndef FUZZING diff --git a/src/messageSigning.h b/src/messageSigning.h index 634ae289..fbf18f89 100644 --- a/src/messageSigning.h +++ b/src/messageSigning.h @@ -7,9 +7,9 @@ void getWitness(bip44_path_t* pathSpec, const uint8_t* txHashBuffer, size_t txHashSize, uint8_t* outBuffer, size_t outSize); -void getGovernanceVotingRegistrationSignature(bip44_path_t* pathSpec, - const uint8_t* payloadHashBuffer, size_t payloadHashSize, - uint8_t* outBuffer, size_t outSize); +void getCVoteRegistrationSignature(bip44_path_t* pathSpec, + const uint8_t* payloadHashBuffer, size_t payloadHashSize, + uint8_t* outBuffer, size_t outSize); void getOpCertSignature(bip44_path_t* pathSpec, const uint8_t* opCertBodyBuffer, size_t opCertBodySize, diff --git a/src/securityPolicy.c b/src/securityPolicy.c index b4838a4c..5e613a75 100644 --- a/src/securityPolicy.c +++ b/src/securityPolicy.c @@ -86,8 +86,8 @@ security_policy_t policyForDerivePrivateKey(const bip44_path_t* path) case PATH_POOL_COLD_KEY: - case PATH_GOVERNANCE_VOTING_ACCOUNT: - case PATH_GOVERNANCE_VOTING_KEY: + case PATH_CVOTE_ACCOUNT: + case PATH_CVOTE_KEY: ALLOW(); break; @@ -146,7 +146,7 @@ security_policy_t policyForGetExtendedPublicKey(const bip44_path_t* pathSpec) PROMPT(); break; - case PATH_GOVERNANCE_VOTING_ACCOUNT: + case PATH_CVOTE_ACCOUNT: WARN_UNLESS(bip44_isPathReasonable(pathSpec)); // in expert mode, do not export keys without permission @@ -159,7 +159,7 @@ security_policy_t policyForGetExtendedPublicKey(const bip44_path_t* pathSpec) case PATH_ORDINARY_STAKING_KEY: case PATH_MULTISIG_SPENDING_KEY: case PATH_MULTISIG_STAKING_KEY: - case PATH_GOVERNANCE_VOTING_KEY: + case PATH_CVOTE_KEY: WARN_UNLESS(bip44_isPathReasonable(pathSpec)); // ask for permission (it is unusual if client asks this instead of the account key) PROMPT(); @@ -185,8 +185,8 @@ security_policy_t policyForGetExtendedPublicKeyBulkExport(const bip44_path_t* pa case PATH_MULTISIG_SPENDING_KEY: case PATH_MULTISIG_STAKING_KEY: case PATH_MINT_KEY: - case PATH_GOVERNANCE_VOTING_ACCOUNT: - case PATH_GOVERNANCE_VOTING_KEY: + case PATH_CVOTE_ACCOUNT: + case PATH_CVOTE_KEY: WARN_UNLESS(bip44_isPathReasonable(pathSpec)); // we do not show these paths since there may be many of them ALLOW(); @@ -976,13 +976,13 @@ security_policy_t policyForSignTxCertificate( case SIGN_TX_SIGNINGMODE_PLUTUS_TX: case SIGN_TX_SIGNINGMODE_ORDINARY_TX: - // pool registration is allowed only in POOL_REGISTRATION signging modes + // pool registration is allowed only in POOL_REGISTRATION signing modes DENY_IF(certificateType == CERTIFICATE_TYPE_STAKE_POOL_REGISTRATION); ALLOW(); break; case SIGN_TX_SIGNINGMODE_MULTISIG_TX: - // pool registration is allowed only in POOL_REGISTRATION signging modes + // pool registration is allowed only in POOL_REGISTRATION signing modes DENY_IF(certificateType == CERTIFICATE_TYPE_STAKE_POOL_REGISTRATION); // pool retirement is impossible with multisig keys DENY_IF(certificateType == CERTIFICATE_TYPE_STAKE_POOL_RETIREMENT); @@ -1541,10 +1541,10 @@ security_policy_t policyForSignTxAuxData(aux_data_type_t auxDataType) SHOW_IF(app_mode_expert()); ALLOW(); - case AUX_DATA_TYPE_CIP36_REGISTRATION: + case AUX_DATA_TYPE_CVOTE_REGISTRATION: // this is the policy for the initial prompt // details of the registration are governed by separate policies - // (see policyForGovernanceVotingRegistration...) + // (see policyForCVoteRegistration...) SHOW(); break; @@ -1590,7 +1590,7 @@ security_policy_t policyForSignTxMintConfirm(security_policy_t mintInitPolicy) break; case POLICY_SHOW_BEFORE_RESPONSE: - // all minted coins were shown, show a final cofirmation prompt as well + // all minted coins were shown, show a final confirmation prompt as well PROMPT(); break; @@ -1756,26 +1756,26 @@ security_policy_t policyForSignTxConfirm() PROMPT(); } -security_policy_t policyForGovernanceVotingRegistrationVotingKey() +security_policy_t policyForCVoteRegistrationVoteKey() { SHOW(); } -security_policy_t policyForGovernanceVotingRegistrationVotingKeyPath( +security_policy_t policyForCVoteRegistrationVoteKeyPath( bip44_path_t* path, - governance_voting_registration_format_t format + cvote_registration_format_t format ) { // encourages people to use the new format, // so that we can drop support for CIP15 sooner DENY_UNLESS(format == CIP36); - DENY_UNLESS(bip44_classifyPath(path) == PATH_GOVERNANCE_VOTING_KEY); + DENY_UNLESS(bip44_classifyPath(path) == PATH_CVOTE_KEY); WARN_UNLESS(bip44_isPathReasonable(path)); SHOW(); } -security_policy_t policyForGovernanceVotingRegistrationStakingKey( +security_policy_t policyForCVoteRegistrationStakingKey( const bip44_path_t* stakingKeyPath ) { @@ -1787,7 +1787,7 @@ security_policy_t policyForGovernanceVotingRegistrationStakingKey( // based on https://input-output-rnd.slack.com/archives/C036XSMFXE3/p1668185230182239 // TODO make sure this is what we want -security_policy_t policyForGovernanceVotingRegistrationVotingRewardsDestination( +security_policy_t policyForCVoteRegistrationPaymentDestination( const tx_output_destination_storage_t* destination, const uint8_t networkId ) @@ -1832,19 +1832,19 @@ security_policy_t policyForGovernanceVotingRegistrationVotingRewardsDestination( } -security_policy_t policyForGovernanceVotingRegistrationNonce() +security_policy_t policyForCVoteRegistrationNonce() { SHOW(); } -security_policy_t policyForGovernanceVotingRegistrationVotingPurpose() +security_policy_t policyForCVoteRegistrationVotingPurpose() { // since it will only be used for Catalyst, we don't show this value to non-experts SHOW_IF(app_mode_expert()); ALLOW(); } -security_policy_t policyForGovernanceVotingRegistrationConfirm() +security_policy_t policyForCVoteRegistrationConfirm() { PROMPT(); } @@ -1869,20 +1869,20 @@ security_policy_t policyForSignOpCert(const bip44_path_t* poolColdKeyPathSpec) DENY(); // should not be reached } -security_policy_t policyForSignGovernanceVoteInit() +security_policy_t policyForSignCVoteInit() { PROMPT(); } -security_policy_t policyForSignGovernanceVoteConfirm() +security_policy_t policyForSignCVoteConfirm() { PROMPT(); } -security_policy_t policyForSignGovernanceVoteWitness(bip44_path_t* path) +security_policy_t policyForSignCVoteWitness(bip44_path_t* path) { switch (bip44_classifyPath(path)) { - case PATH_GOVERNANCE_VOTING_KEY: + case PATH_CVOTE_KEY: WARN_UNLESS(bip44_isPathReasonable(path)); SHOW(); break; diff --git a/src/securityPolicy.h b/src/securityPolicy.h index 7bf29396..37613d7c 100644 --- a/src/securityPolicy.h +++ b/src/securityPolicy.h @@ -187,24 +187,24 @@ security_policy_t policyForSignTxConfirm(); security_policy_t policyForSignOpCert(const bip44_path_t* poolColdKeyPathSpec); -security_policy_t policyForGovernanceVotingRegistrationVotingKey(); -security_policy_t policyForGovernanceVotingRegistrationVotingKeyPath( +security_policy_t policyForCVoteRegistrationVoteKey(); +security_policy_t policyForCVoteRegistrationVoteKeyPath( bip44_path_t* path, - governance_voting_registration_format_t format + cvote_registration_format_t format ); -security_policy_t policyForGovernanceVotingRegistrationStakingKey( +security_policy_t policyForCVoteRegistrationStakingKey( const bip44_path_t* stakingKeyPath ); -security_policy_t policyForGovernanceVotingRegistrationVotingRewardsDestination( +security_policy_t policyForCVoteRegistrationPaymentDestination( const tx_output_destination_storage_t* destination, const uint8_t networkId ); -security_policy_t policyForGovernanceVotingRegistrationNonce(); -security_policy_t policyForGovernanceVotingRegistrationVotingPurpose(); -security_policy_t policyForGovernanceVotingRegistrationConfirm(); +security_policy_t policyForCVoteRegistrationNonce(); +security_policy_t policyForCVoteRegistrationVotingPurpose(); +security_policy_t policyForCVoteRegistrationConfirm(); -security_policy_t policyForSignGovernanceVoteInit(); -security_policy_t policyForSignGovernanceVoteConfirm(); -security_policy_t policyForSignGovernanceVoteWitness(bip44_path_t* path); +security_policy_t policyForSignCVoteInit(); +security_policy_t policyForSignCVoteConfirm(); +security_policy_t policyForSignCVoteWitness(bip44_path_t* path); #endif // H_CARDANO_APP_SECURITY_POLICY diff --git a/src/signGovernanceVote.c b/src/signCVote.c similarity index 91% rename from src/signGovernanceVote.c rename to src/signCVote.c index 1f99a563..1cc4c20d 100644 --- a/src/signGovernanceVote.c +++ b/src/signCVote.c @@ -1,15 +1,15 @@ #include "messageSigning.h" #include "securityPolicy.h" -#include "signGovernanceVote.h" +#include "signCVote.h" #include "signTxUtils.h" #include "state.h" #include "uiScreens.h" -static ins_sign_governance_vote_context_t* ctx = &(instructionState.signGovernanceVoteContext); +static ins_sign_cvote_context_t* ctx = &(instructionState.signCVoteContext); static void advanceStage() { - TRACE("Advancing governance voting stage from: %d", ctx->stage); + TRACE("Advancing cip36 voting stage from: %d", ctx->stage); switch (ctx->stage) { case VOTECAST_STAGE_INIT: @@ -43,11 +43,11 @@ static void advanceStage() } - TRACE("Advancing governance voting stage to: %d", ctx->stage); + TRACE("Advancing cip36 voting stage to: %d", ctx->stage); } // this is supposed to be called at the beginning of each APDU handler -static inline void CHECK_STAGE(sign_governance_vote_stage_t expected) +static inline void CHECK_STAGE(sign_cvote_stage_t expected) { TRACE("Checking stage... current one is %d, expected %d", ctx->stage, expected); VALIDATE(ctx->stage == expected, ERR_INVALID_STATE); @@ -73,7 +73,7 @@ static void handleInit_ui_runStep() UI_STEP(HANDLE_INIT_CONFIRM_START) { ui_displayPrompt( "Start new", - "governance vote?", + "vote? (CIP-36)", this_fn, respond_with_user_reject ); @@ -107,7 +107,7 @@ static void handleInit_ui_runStep() } __noinline_due_to_stack__ -void signGovernanceVote_handleInitAPDU( +void signCVote_handleInitAPDU( const uint8_t* wireDataBuffer, size_t wireDataSize ) { @@ -141,7 +141,7 @@ void signGovernanceVote_handleInitAPDU( } // Check security policy - security_policy_t policy = policyForSignGovernanceVoteInit(); + security_policy_t policy = policyForSignCVoteInit(); ENSURE_NOT_DENIED(policy); { @@ -174,7 +174,7 @@ void signGovernanceVote_handleInitAPDU( // ============================== VOTECAST CHUNK ============================== __noinline_due_to_stack__ -void signGovernanceVote_handleVotecastChunkAPDU( +void signCVote_handleVotecastChunkAPDU( const uint8_t* wireDataBuffer, size_t wireDataSize ) { @@ -237,7 +237,7 @@ static void handleConfirm_ui_runStep() } __noinline_due_to_stack__ -void signGovernanceVote_handleConfirmAPDU( +void signCVote_handleConfirmAPDU( const uint8_t* wireDataBuffer MARK_UNUSED, size_t wireDataSize ) { @@ -252,7 +252,7 @@ void signGovernanceVote_handleConfirmAPDU( VALIDATE(wireDataSize == 0, ERR_INVALID_DATA); } - security_policy_t policy = policyForSignGovernanceVoteConfirm(); + security_policy_t policy = policyForSignCVoteConfirm(); TRACE("Policy: %d", (int) policy); ENSURE_NOT_DENIED(policy); @@ -335,7 +335,7 @@ static void handleWitness_ui_runStep() } __noinline_due_to_stack__ -void signGovernanceVote_handleWitnessAPDU( +void signCVote_handleWitnessAPDU( const uint8_t* wireDataBuffer, size_t wireDataSize ) { @@ -358,13 +358,13 @@ void signGovernanceVote_handleWitnessAPDU( PRINTF("\n"); } - security_policy_t policy = policyForSignGovernanceVoteWitness(&ctx->witnessData.path); + security_policy_t policy = policyForSignCVoteWitness(&ctx->witnessData.path); TRACE("Policy: %d", (int) policy); ENSURE_NOT_DENIED(policy); { // compute witness - TRACE("getGovernanceVoteWitness"); + TRACE("getCVoteWitness"); TRACE("votecast hash:"); TRACE_BUFFER(ctx->votecastHash, SIZEOF(ctx->votecastHash)); @@ -400,17 +400,17 @@ static subhandler_fn_t* lookup_subhandler(uint8_t p1) switch (p1) { #define CASE(P1, HANDLER) case P1: return HANDLER; #define DEFAULT(HANDLER) default: return HANDLER; - CASE(0x01, signGovernanceVote_handleInitAPDU); - CASE(0x02, signGovernanceVote_handleVotecastChunkAPDU); - CASE(0x03, signGovernanceVote_handleConfirmAPDU); - CASE(0x04, signGovernanceVote_handleWitnessAPDU); + CASE(0x01, signCVote_handleInitAPDU); + CASE(0x02, signCVote_handleVotecastChunkAPDU); + CASE(0x03, signCVote_handleConfirmAPDU); + CASE(0x04, signCVote_handleWitnessAPDU); DEFAULT(NULL) #undef CASE #undef DEFAULT } } -void signGovernanceVote_handleAPDU( +void signCVote_handleAPDU( uint8_t p1, uint8_t p2, const uint8_t* wireDataBuffer, diff --git a/src/signGovernanceVote.h b/src/signCVote.h similarity index 73% rename from src/signGovernanceVote.h rename to src/signCVote.h index 2bc01df2..42eab7dd 100644 --- a/src/signGovernanceVote.h +++ b/src/signCVote.h @@ -1,5 +1,5 @@ -#ifndef H_CARDANO_APP_SIGN_GOVERNANCE_VOTE -#define H_CARDANO_APP_SIGN_GOVERNANCE_VOTE +#ifndef H_CARDANO_APP_SIGN_CVOTE +#define H_CARDANO_APP_SIGN_CVOTE #include "cardano.h" #include "common.h" @@ -16,10 +16,10 @@ typedef enum { VOTECAST_STAGE_CHUNK = 40, VOTECAST_STAGE_CONFIRM = 60, VOTECAST_STAGE_WITNESS = 80, -} sign_governance_vote_stage_t; +} sign_cvote_stage_t; typedef struct { - sign_governance_vote_stage_t stage; + sign_cvote_stage_t stage; int ui_step; size_t remainingVotecastBytes; @@ -38,8 +38,8 @@ typedef struct { uint8_t signature[ED25519_SIGNATURE_LENGTH]; } witnessData; }; -} ins_sign_governance_vote_context_t; +} ins_sign_cvote_context_t; -handler_fn_t signGovernanceVote_handleAPDU; +handler_fn_t signCVote_handleAPDU; -#endif // H_CARDANO_APP_SIGN_GOVERNANCE_VOTE +#endif // H_CARDANO_APP_SIGN_CVOTE diff --git a/src/signTx.c b/src/signTx.c index c36f8d2d..bee1171c 100644 --- a/src/signTx.c +++ b/src/signTx.c @@ -365,15 +365,15 @@ static inline void checkForFinishedSubmachines() } break; - case SIGN_STAGE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_SUBMACHINE: - if (signTxGovernanceVotingRegistration_isFinished()) { + case SIGN_STAGE_AUX_DATA_CVOTE_REGISTRATION_SUBMACHINE: + if (signTxCVoteRegistration_isFinished()) { TRACE(); ctx->stage = SIGN_STAGE_AUX_DATA; AUX_DATA_CTX->auxDataReceived = true; STATIC_ASSERT(SIZEOF(ctx->auxDataHash) == AUX_DATA_HASH_LENGTH, "Wrong auxiliary data hash length"); - STATIC_ASSERT(SIZEOF(AUX_DATA_CTX->stageContext.governance_voting_registration_subctx.auxDataHash) == AUX_DATA_HASH_LENGTH, "Wrong auxiliary data hash length"); - memmove(ctx->auxDataHash, AUX_DATA_CTX->stageContext.governance_voting_registration_subctx.auxDataHash, AUX_DATA_HASH_LENGTH); + STATIC_ASSERT(SIZEOF(AUX_DATA_CTX->stageContext.cvote_registration_subctx.auxDataHash) == AUX_DATA_HASH_LENGTH, "Wrong auxiliary data hash length"); + memmove(ctx->auxDataHash, AUX_DATA_CTX->stageContext.cvote_registration_subctx.auxDataHash, AUX_DATA_HASH_LENGTH); advanceStage(); } @@ -482,7 +482,7 @@ static void signTx_handleInit_ui_runStep() // technically, no pool reg. certificate as well, but the UI message would be too long ui_displayPaginatedText( "Warning:", - "cannot verify network id: no outputs or withrawals", + "cannot verify network id: no outputs or withdrawals", this_fn ); } @@ -726,33 +726,33 @@ static void signTx_handleAuxDataArbitraryHash_ui_runStep() enum { - HANDLE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_STEP_DISPLAY = 850, - HANDLE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_STEP_RESPOND, - HANDLE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_STEP_INVALID, + HANDLE_AUX_DATA_CVOTE_REGISTRATION_STEP_DISPLAY = 850, + HANDLE_AUX_DATA_CVOTE_REGISTRATION_STEP_RESPOND, + HANDLE_AUX_DATA_CVOTE_REGISTRATION_STEP_INVALID, }; -static void signTx_handleAuxDataGovernanceVotingRegistration_ui_runStep() +static void signTx_handleAuxDataCVoteRegistration_ui_runStep() { TRACE("UI step %d", ctx->ui_step); TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTx_handleAuxDataGovernanceVotingRegistration_ui_runStep; + ui_callback_fn_t* this_fn = signTx_handleAuxDataCVoteRegistration_ui_runStep; UI_STEP_BEGIN(ctx->ui_step, this_fn); - UI_STEP(HANDLE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_STEP_DISPLAY) { + UI_STEP(HANDLE_AUX_DATA_CVOTE_REGISTRATION_STEP_DISPLAY) { ui_displayPrompt( - "Register governance", - "vote key?", + "Register vote", + "key (CIP-36)?", this_fn, respond_with_user_reject ); } - UI_STEP(HANDLE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_STEP_RESPOND) { + UI_STEP(HANDLE_AUX_DATA_CVOTE_REGISTRATION_STEP_RESPOND) { respondSuccessEmptyMsg(); - signTxGovernanceVotingRegistration_init(); - ctx->stage = SIGN_STAGE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_SUBMACHINE; + signTxCVoteRegistration_init(); + ctx->stage = SIGN_STAGE_AUX_DATA_CVOTE_REGISTRATION_SUBMACHINE; } - UI_STEP_END(HANDLE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_STEP_INVALID); + UI_STEP_END(HANDLE_AUX_DATA_CVOTE_REGISTRATION_STEP_INVALID); } __noinline_due_to_stack__ @@ -763,14 +763,14 @@ static void signTx_handleAuxDataAPDU(uint8_t p2, const uint8_t* wireDataBuffer, ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); ASSERT(ctx->includeAuxData == true); - // delegate to state sub-machine for governance voting registration data - if (signTxGovernanceVotingRegistration_isValidInstruction(p2)) { + // delegate to state sub-machine for CIP-36 voting registration data + if (signTxCVoteRegistration_isValidInstruction(p2)) { TRACE(); - CHECK_STAGE(SIGN_STAGE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_SUBMACHINE); + CHECK_STAGE(SIGN_STAGE_AUX_DATA_CVOTE_REGISTRATION_SUBMACHINE); TRACE_STACK_USAGE(); - signTxGovernanceVotingRegistration_handleAPDU(p2, wireDataBuffer, wireDataSize); + signTxCVoteRegistration_handleAPDU(p2, wireDataBuffer, wireDataSize); return; } @@ -794,7 +794,7 @@ static void signTx_handleAuxDataAPDU(uint8_t p2, const uint8_t* wireDataBuffer, break; } - case AUX_DATA_TYPE_CIP36_REGISTRATION: + case AUX_DATA_TYPE_CVOTE_REGISTRATION: break; default: @@ -823,18 +823,18 @@ static void signTx_handleAuxDataAPDU(uint8_t p2, const uint8_t* wireDataBuffer, signTx_handleAuxDataArbitraryHash_ui_runStep(); break; } - case AUX_DATA_TYPE_CIP36_REGISTRATION: + case AUX_DATA_TYPE_CVOTE_REGISTRATION: // select UI step switch (policy) { #define CASE(POLICY, UI_STEP) case POLICY: {ctx->ui_step=UI_STEP; break;} - CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_STEP_DISPLAY); - CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_STEP_RESPOND); + CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_AUX_DATA_CVOTE_REGISTRATION_STEP_DISPLAY); + CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_AUX_DATA_CVOTE_REGISTRATION_STEP_RESPOND); #undef CASE default: THROW(ERR_NOT_IMPLEMENTED); } - signTx_handleAuxDataGovernanceVotingRegistration_ui_runStep(); + signTx_handleAuxDataCVoteRegistration_ui_runStep(); break; default: ASSERT(false); @@ -901,7 +901,7 @@ static void constructInputLabel(const char* prefix, uint16_t index) char* label = BODY_CTX->stageData.input.label; const size_t labelSize = SIZEOF(BODY_CTX->stageData.input.label); explicit_bzero(label, labelSize); - // indexed from 0 as agreed with IOHK on Slack + // indexed from 0 as agreed with IOG on Slack snprintf(label, labelSize, "%s #%u", prefix, index); // make sure all the information is displayed to the user ASSERT(strlen(label) + 1 < labelSize); @@ -2572,7 +2572,7 @@ ins_sign_tx_aux_data_context_t* accessAuxDataContext() switch (ctx->stage) { case SIGN_STAGE_AUX_DATA: - case SIGN_STAGE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_SUBMACHINE: + case SIGN_STAGE_AUX_DATA_CVOTE_REGISTRATION_SUBMACHINE: return &(ctx->txPartCtx.aux_data_ctx); default: diff --git a/src/signTx.h b/src/signTx.h index c797df27..d50db9c9 100644 --- a/src/signTx.h +++ b/src/signTx.h @@ -10,7 +10,7 @@ #include "signTxMint.h" #include "signTxOutput.h" #include "signTxPoolRegistration.h" -#include "signTxGovernanceVotingRegistration.h" +#include "signTxCVoteRegistration.h" #include "signTxAuxData.h" // the signing mode significantly affects restrictions on tx being signed @@ -26,7 +26,7 @@ typedef enum { SIGN_STAGE_NONE = 0, SIGN_STAGE_INIT = 23, SIGN_STAGE_AUX_DATA = 24, - SIGN_STAGE_AUX_DATA_GOVERNANCE_VOTING_REGISTRATION_SUBMACHINE = 25, + SIGN_STAGE_AUX_DATA_CVOTE_REGISTRATION_SUBMACHINE = 25, SIGN_STAGE_BODY_INPUTS = 26, SIGN_STAGE_BODY_OUTPUTS = 27, SIGN_STAGE_BODY_OUTPUTS_SUBMACHINE = 28, @@ -121,7 +121,7 @@ typedef struct { aux_data_hash_builder_t auxDataHashBuilder; struct { - governance_voting_registration_context_t governance_voting_registration_subctx; + cvote_registration_context_t cvote_registration_subctx; } stageContext; } ins_sign_tx_aux_data_context_t; diff --git a/src/signTxAuxData.h b/src/signTxAuxData.h index d416192b..1e766fd9 100644 --- a/src/signTxAuxData.h +++ b/src/signTxAuxData.h @@ -3,7 +3,7 @@ typedef enum { AUX_DATA_TYPE_ARBITRARY_HASH = 0, - AUX_DATA_TYPE_CIP36_REGISTRATION = 1, + AUX_DATA_TYPE_CVOTE_REGISTRATION = 1, } aux_data_type_t; #endif // H_CARDANO_APP_SIGN_TX_AUX_DATA diff --git a/src/signTxGovernanceVotingRegistration.c b/src/signTxCVoteRegistration.c similarity index 56% rename from src/signTxGovernanceVotingRegistration.c rename to src/signTxCVoteRegistration.c index b3eb8f8d..50bed876 100644 --- a/src/signTxGovernanceVotingRegistration.c +++ b/src/signTxCVoteRegistration.c @@ -1,5 +1,5 @@ #include "app_mode.h" -#include "signTxGovernanceVotingRegistration.h" +#include "signTxCVoteRegistration.h" #include "state.h" #include "uiHelpers.h" #include "signTxUtils.h" @@ -13,28 +13,28 @@ static common_tx_data_t* commonTxData = &(instructionState.signTxContext.commonTxData); -static inline governance_voting_registration_context_t* accessSubContext() +static inline cvote_registration_context_t* accessSubContext() { - return &AUX_DATA_CTX->stageContext.governance_voting_registration_subctx; + return &AUX_DATA_CTX->stageContext.cvote_registration_subctx; } -bool signTxGovernanceVotingRegistration_isFinished() +bool signTxCVoteRegistration_isFinished() { - const governance_voting_registration_context_t* subctx = accessSubContext(); - TRACE("Governance voting registration submachine state: %d", subctx->state); + const cvote_registration_context_t* subctx = accessSubContext(); + TRACE("CIP-36 voting registration submachine state: %d", subctx->state); // we are also asserting that the state is valid switch (subctx->state) { - case STATE_GOVERNANCE_VOTING_REGISTRATION_FINISHED: + case STATE_CVOTE_REGISTRATION_FINISHED: return true; - case STATE_GOVERNANCE_VOTING_REGISTRATION_INIT: - case STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_KEY: - case STATE_GOVERNANCE_VOTING_REGISTRATION_DELEGATIONS: - case STATE_GOVERNANCE_VOTING_REGISTRATION_STAKING_KEY: - case STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_REWARDS_ADDRESS: - case STATE_GOVERNANCE_VOTING_REGISTRATION_NONCE: - case STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_PURPOSE: - case STATE_GOVERNANCE_VOTING_REGISTRATION_CONFIRM: + case STATE_CVOTE_REGISTRATION_INIT: + case STATE_CVOTE_REGISTRATION_VOTE_KEY: + case STATE_CVOTE_REGISTRATION_DELEGATIONS: + case STATE_CVOTE_REGISTRATION_STAKING_KEY: + case STATE_CVOTE_REGISTRATION_PAYMENT_ADDRESS: + case STATE_CVOTE_REGISTRATION_NONCE: + case STATE_CVOTE_REGISTRATION_VOTING_PURPOSE: + case STATE_CVOTE_REGISTRATION_CONFIRM: return false; default: @@ -42,86 +42,86 @@ bool signTxGovernanceVotingRegistration_isFinished() } } -void signTxGovernanceVotingRegistration_init() +void signTxCVoteRegistration_init() { explicit_bzero(&AUX_DATA_CTX->stageContext, SIZEOF(AUX_DATA_CTX->stageContext)); auxDataHashBuilder_init(&AUX_DATA_CTX->auxDataHashBuilder); - accessSubContext()->state = STATE_GOVERNANCE_VOTING_REGISTRATION_INIT; + accessSubContext()->state = STATE_CVOTE_REGISTRATION_INIT; } -static inline void CHECK_STATE(sign_tx_governance_voting_registration_state_t expected) +static inline void CHECK_STATE(sign_tx_cvote_registration_state_t expected) { - TRACE("Governance voting registration submachine state: current %d, expected %d", accessSubContext()->state, expected); + TRACE("CIP-36 voting registration submachine state: current %d, expected %d", accessSubContext()->state, expected); VALIDATE(accessSubContext()->state == expected, ERR_INVALID_STATE); } static inline void advanceState() { - governance_voting_registration_context_t* subctx = accessSubContext(); - TRACE("Advancing governance voting registration state from: %d", subctx->state); + cvote_registration_context_t* subctx = accessSubContext(); + TRACE("Advancing CIP-36 voting registration state from: %d", subctx->state); switch (subctx->state) { - case STATE_GOVERNANCE_VOTING_REGISTRATION_INIT: + case STATE_CVOTE_REGISTRATION_INIT: if (subctx->numDelegations > 0) { - subctx->state = STATE_GOVERNANCE_VOTING_REGISTRATION_DELEGATIONS; - auxDataHashBuilder_governanceVotingRegistration_enterDelegations( + subctx->state = STATE_CVOTE_REGISTRATION_DELEGATIONS; + auxDataHashBuilder_cVoteRegistration_enterDelegations( &AUX_DATA_CTX->auxDataHashBuilder, subctx->numDelegations ); } else { - // we expect a single voting key - subctx->state = STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_KEY; + // we expect a single vote key + subctx->state = STATE_CVOTE_REGISTRATION_VOTE_KEY; } break; - case STATE_GOVERNANCE_VOTING_REGISTRATION_DELEGATIONS: + case STATE_CVOTE_REGISTRATION_DELEGATIONS: ASSERT(subctx->currentDelegation == subctx->numDelegations); - subctx->state = STATE_GOVERNANCE_VOTING_REGISTRATION_STAKING_KEY; + subctx->state = STATE_CVOTE_REGISTRATION_STAKING_KEY; break; - case STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_KEY: - subctx->state = STATE_GOVERNANCE_VOTING_REGISTRATION_STAKING_KEY; + case STATE_CVOTE_REGISTRATION_VOTE_KEY: + subctx->state = STATE_CVOTE_REGISTRATION_STAKING_KEY; break; - case STATE_GOVERNANCE_VOTING_REGISTRATION_STAKING_KEY: - subctx->state = STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_REWARDS_ADDRESS; + case STATE_CVOTE_REGISTRATION_STAKING_KEY: + subctx->state = STATE_CVOTE_REGISTRATION_PAYMENT_ADDRESS; break; - case STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_REWARDS_ADDRESS: - subctx->state = STATE_GOVERNANCE_VOTING_REGISTRATION_NONCE; + case STATE_CVOTE_REGISTRATION_PAYMENT_ADDRESS: + subctx->state = STATE_CVOTE_REGISTRATION_NONCE; break; - case STATE_GOVERNANCE_VOTING_REGISTRATION_NONCE: - subctx->state = STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_PURPOSE; + case STATE_CVOTE_REGISTRATION_NONCE: + subctx->state = STATE_CVOTE_REGISTRATION_VOTING_PURPOSE; break; - case STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_PURPOSE: - subctx->state = STATE_GOVERNANCE_VOTING_REGISTRATION_CONFIRM; + case STATE_CVOTE_REGISTRATION_VOTING_PURPOSE: + subctx->state = STATE_CVOTE_REGISTRATION_CONFIRM; break; - case STATE_GOVERNANCE_VOTING_REGISTRATION_CONFIRM: - subctx->state = STATE_GOVERNANCE_VOTING_REGISTRATION_FINISHED; + case STATE_CVOTE_REGISTRATION_CONFIRM: + subctx->state = STATE_CVOTE_REGISTRATION_FINISHED; break; default: ASSERT(false); } - TRACE("Advancing governance voting registration state to: %d", subctx->state); + TRACE("Advancing CIP-36 voting registration state to: %d", subctx->state); } // ============================== INIT ============================== -static void signTxGovernanceVotingRegistration_handleInitAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) +static void signTxCVoteRegistration_handleInitAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) { { - CHECK_STATE(STATE_GOVERNANCE_VOTING_REGISTRATION_INIT); + CHECK_STATE(STATE_CVOTE_REGISTRATION_INIT); ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); } - governance_voting_registration_context_t* subctx = accessSubContext(); + cvote_registration_context_t* subctx = accessSubContext(); { explicit_bzero(&subctx->stateData, SIZEOF(subctx->stateData)); } @@ -132,7 +132,7 @@ static void signTxGovernanceVotingRegistration_handleInitAPDU(const uint8_t* wir read_view_t view = make_read_view(wireDataBuffer, wireDataBuffer + wireDataSize); subctx->format = parse_u1be(&view); - TRACE("Governance voting registration format = %d", (int) subctx->format); + TRACE("CIP-36 voting registration format = %d", (int) subctx->format); switch (subctx->format) { case CIP15: case CIP36: @@ -153,8 +153,8 @@ static void signTxGovernanceVotingRegistration_handleInitAPDU(const uint8_t* wir } { aux_data_hash_builder_t* auxDataHashBuilder = &AUX_DATA_CTX->auxDataHashBuilder; - auxDataHashBuilder_governanceVotingRegistration_enter(auxDataHashBuilder, subctx->format); - auxDataHashBuilder_governanceVotingRegistration_enterPayload(auxDataHashBuilder); + auxDataHashBuilder_cVoteRegistration_enter(auxDataHashBuilder, subctx->format); + auxDataHashBuilder_cVoteRegistration_enterPayload(auxDataHashBuilder); } respondSuccessEmptyMsg(); @@ -163,9 +163,9 @@ static void signTxGovernanceVotingRegistration_handleInitAPDU(const uint8_t* wir // ============================== VOTING KEY ============================== -static void _parseVotingKey(read_view_t* view) +static void _parseVoteKey(read_view_t* view) { - governance_voting_registration_context_t* subctx = accessSubContext(); + cvote_registration_context_t* subctx = accessSubContext(); subctx->stateData.delegation.type = parse_u1be(view); TRACE("delegation type = %d", (int) subctx->stateData.delegation.type); @@ -173,13 +173,13 @@ static void _parseVotingKey(read_view_t* view) case DELEGATION_KEY: { STATIC_ASSERT( - SIZEOF(subctx->stateData.delegation.votingPubKey) == GOVERNANCE_VOTING_PUBLIC_KEY_LENGTH, - "wrong voting public key size" + SIZEOF(subctx->stateData.delegation.votePubKey) == CVOTE_PUBLIC_KEY_LENGTH, + "wrong vote public key size" ); view_parseBuffer( - subctx->stateData.delegation.votingPubKey, + subctx->stateData.delegation.votePubKey, view, - GOVERNANCE_VOTING_PUBLIC_KEY_LENGTH + CVOTE_PUBLIC_KEY_LENGTH ); break; } @@ -188,12 +188,12 @@ static void _parseVotingKey(read_view_t* view) view_skipBytes( view, bip44_parseFromWire( - &subctx->stateData.delegation.votingPubKeyPath, + &subctx->stateData.delegation.votePubKeyPath, VIEW_REMAINING_TO_TUPLE_BUF_SIZE(view) ) ); TRACE(); - BIP44_PRINTF(&subctx->stateData.delegation.votingPubKeyPath); + BIP44_PRINTF(&subctx->stateData.delegation.votePubKeyPath); PRINTF("\n"); break; } @@ -203,20 +203,20 @@ static void _parseVotingKey(read_view_t* view) } } -security_policy_t _determineVotingKeyPolicy() +security_policy_t _determineVoteKeyPolicy() { - governance_voting_registration_context_t* subctx = accessSubContext(); + cvote_registration_context_t* subctx = accessSubContext(); switch (subctx->stateData.delegation.type) { case DELEGATION_PATH: - return policyForGovernanceVotingRegistrationVotingKeyPath( - &subctx->stateData.delegation.votingPubKeyPath, + return policyForCVoteRegistrationVoteKeyPath( + &subctx->stateData.delegation.votePubKeyPath, subctx->format ); case DELEGATION_KEY: - return policyForGovernanceVotingRegistrationVotingKey(); + return policyForCVoteRegistrationVoteKey(); default: ASSERT(false); @@ -224,16 +224,16 @@ security_policy_t _determineVotingKeyPolicy() return POLICY_DENY; } -static void _displayVotingKey(ui_callback_fn_t callback) +static void _displayVoteKey(ui_callback_fn_t callback) { - governance_voting_registration_context_t* subctx = accessSubContext(); + cvote_registration_context_t* subctx = accessSubContext(); switch (subctx->stateData.delegation.type) { case DELEGATION_KEY: { - STATIC_ASSERT(SIZEOF(subctx->stateData.delegation.votingPubKey) == GOVERNANCE_VOTING_PUBLIC_KEY_LENGTH, "wrong voting public key size"); + STATIC_ASSERT(SIZEOF(subctx->stateData.delegation.votePubKey) == CVOTE_PUBLIC_KEY_LENGTH, "wrong vote public key size"); ui_displayBech32Screen( "Vote public key", "cvote_vk", - subctx->stateData.delegation.votingPubKey, GOVERNANCE_VOTING_PUBLIC_KEY_LENGTH, + subctx->stateData.delegation.votePubKey, CVOTE_PUBLIC_KEY_LENGTH, callback ); break; @@ -241,7 +241,7 @@ static void _displayVotingKey(ui_callback_fn_t callback) case DELEGATION_PATH: { ui_displayPathScreen( "Vote public key", - &subctx->stateData.delegation.votingPubKeyPath, + &subctx->stateData.delegation.votePubKeyPath, callback ); break; @@ -252,47 +252,47 @@ static void _displayVotingKey(ui_callback_fn_t callback) } enum { - HANDLE_VOTING_KEY_STEP_WARNING = 8200, - HANDLE_VOTING_KEY_STEP_DISPLAY, - HANDLE_VOTING_KEY_STEP_RESPOND, - HANDLE_VOTING_KEY_STEP_INVALID, + HANDLE_VOTE_KEY_STEP_WARNING = 8200, + HANDLE_VOTE_KEY_STEP_DISPLAY, + HANDLE_VOTE_KEY_STEP_RESPOND, + HANDLE_VOTE_KEY_STEP_INVALID, }; -static void signTxGovernanceVotingRegistration_handleVotingKey_ui_runStep() +static void signTxCVoteRegistration_handleVoteKey_ui_runStep() { - governance_voting_registration_context_t* subctx = accessSubContext(); + cvote_registration_context_t* subctx = accessSubContext(); TRACE("UI step %d", subctx->ui_step); TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTxGovernanceVotingRegistration_handleVotingKey_ui_runStep; + ui_callback_fn_t* this_fn = signTxCVoteRegistration_handleVoteKey_ui_runStep; UI_STEP_BEGIN(subctx->ui_step, this_fn); - UI_STEP(HANDLE_VOTING_KEY_STEP_WARNING) { + UI_STEP(HANDLE_VOTE_KEY_STEP_WARNING) { ui_displayPaginatedText( "WARNING:", "unusual vote key", this_fn ); } - UI_STEP(HANDLE_VOTING_KEY_STEP_DISPLAY) { - _displayVotingKey(this_fn); + UI_STEP(HANDLE_VOTE_KEY_STEP_DISPLAY) { + _displayVoteKey(this_fn); } - UI_STEP(HANDLE_VOTING_KEY_STEP_RESPOND) { + UI_STEP(HANDLE_VOTE_KEY_STEP_RESPOND) { respondSuccessEmptyMsg(); advanceState(); } - UI_STEP_END(HANDLE_VOTING_KEY_STEP_INVALID); + UI_STEP_END(HANDLE_VOTE_KEY_STEP_INVALID); } __noinline_due_to_stack__ -static void signTxGovernanceVotingRegistration_handleVotingKeyAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) +static void signTxCVoteRegistration_handleVoteKeyAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) { { - CHECK_STATE(STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_KEY); + CHECK_STATE(STATE_CVOTE_REGISTRATION_VOTE_KEY); ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); } - governance_voting_registration_context_t* subctx = accessSubContext(); + cvote_registration_context_t* subctx = accessSubContext(); { explicit_bzero(&subctx->stateData, SIZEOF(subctx->stateData)); } @@ -300,12 +300,12 @@ static void signTxGovernanceVotingRegistration_handleVotingKeyAPDU(const uint8_t TRACE_BUFFER(wireDataBuffer, wireDataSize); read_view_t view = make_read_view(wireDataBuffer, wireDataBuffer + wireDataSize); - _parseVotingKey(&view); + _parseVoteKey(&view); VALIDATE(view_remainingSize(&view) == 0, ERR_INVALID_DATA); } - security_policy_t policy = _determineVotingKeyPolicy(); + security_policy_t policy = _determineVoteKeyPolicy(); TRACE("Policy: %d", (int) policy); ENSURE_NOT_DENIED(policy); @@ -316,18 +316,18 @@ static void signTxGovernanceVotingRegistration_handleVotingKeyAPDU(const uint8_t switch (subctx->stateData.delegation.type) { case DELEGATION_KEY: { - auxDataHashBuilder_governanceVotingRegistration_addVotingKey( - auxDataHashBuilder, subctx->stateData.delegation.votingPubKey, - GOVERNANCE_VOTING_PUBLIC_KEY_LENGTH + auxDataHashBuilder_cVoteRegistration_addVoteKey( + auxDataHashBuilder, subctx->stateData.delegation.votePubKey, + CVOTE_PUBLIC_KEY_LENGTH ); break; } case DELEGATION_PATH: { - extendedPublicKey_t extVotingPubKey; - deriveExtendedPublicKey(&subctx->stateData.delegation.votingPubKeyPath, &extVotingPubKey); - auxDataHashBuilder_governanceVotingRegistration_addVotingKey( - auxDataHashBuilder, extVotingPubKey.pubKey, SIZEOF(extVotingPubKey.pubKey) + extendedPublicKey_t extVotePubKey; + deriveExtendedPublicKey(&subctx->stateData.delegation.votePubKeyPath, &extVotePubKey); + auxDataHashBuilder_cVoteRegistration_addVoteKey( + auxDataHashBuilder, extVotePubKey.pubKey, SIZEOF(extVotePubKey.pubKey) ); break; } @@ -341,46 +341,46 @@ static void signTxGovernanceVotingRegistration_handleVotingKeyAPDU(const uint8_t // select UI steps switch (policy) { #define CASE(POLICY, UI_STEP) case POLICY: {subctx->ui_step=UI_STEP; break;} - CASE(POLICY_PROMPT_WARN_UNUSUAL, HANDLE_VOTING_KEY_STEP_WARNING); - CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_VOTING_KEY_STEP_DISPLAY); - CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_VOTING_KEY_STEP_RESPOND); + CASE(POLICY_PROMPT_WARN_UNUSUAL, HANDLE_VOTE_KEY_STEP_WARNING); + CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_VOTE_KEY_STEP_DISPLAY); + CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_VOTE_KEY_STEP_RESPOND); #undef CASE default: THROW(ERR_NOT_IMPLEMENTED); } } - signTxGovernanceVotingRegistration_handleVotingKey_ui_runStep(); + signTxCVoteRegistration_handleVoteKey_ui_runStep(); } // ============================== DELEGATION ============================== enum { HANDLE_DELEGATION_STEP_WARNING = 8300, - HANDLE_DELEGATION_STEP_VOTING_KEY, + HANDLE_DELEGATION_STEP_VOTE_KEY, HANDLE_DELEGATION_STEP_WEIGHT, HANDLE_DELEGATION_STEP_RESPOND, HANDLE_DELEGATION_STEP_INVALID, }; -static void signTxGovernanceVotingRegistration_handleDelegation_ui_runStep() +static void signTxCVoteRegistration_handleDelegation_ui_runStep() { - governance_voting_registration_context_t* subctx = accessSubContext(); + cvote_registration_context_t* subctx = accessSubContext(); TRACE("UI step %d", subctx->ui_step); TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTxGovernanceVotingRegistration_handleDelegation_ui_runStep; + ui_callback_fn_t* this_fn = signTxCVoteRegistration_handleDelegation_ui_runStep; UI_STEP_BEGIN(subctx->ui_step, this_fn); - UI_STEP(HANDLE_VOTING_KEY_STEP_WARNING) { + UI_STEP(HANDLE_VOTE_KEY_STEP_WARNING) { ui_displayPaginatedText( "WARNING:", "unusual vote key", this_fn ); } - UI_STEP(HANDLE_DELEGATION_STEP_VOTING_KEY) { - _displayVotingKey(this_fn); + UI_STEP(HANDLE_DELEGATION_STEP_VOTE_KEY) { + _displayVoteKey(this_fn); } UI_STEP(HANDLE_DELEGATION_STEP_WEIGHT) { ui_displayUint64Screen( @@ -400,11 +400,11 @@ static void signTxGovernanceVotingRegistration_handleDelegation_ui_runStep() } __noinline_due_to_stack__ -static void signTxGovernanceVotingRegistration_handleDelegationAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) +static void signTxCVoteRegistration_handleDelegationAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) { - governance_voting_registration_context_t* subctx = accessSubContext(); + cvote_registration_context_t* subctx = accessSubContext(); { - CHECK_STATE(STATE_GOVERNANCE_VOTING_REGISTRATION_DELEGATIONS); + CHECK_STATE(STATE_CVOTE_REGISTRATION_DELEGATIONS); ASSERT(subctx->currentDelegation < subctx->numDelegations); } { @@ -414,16 +414,16 @@ static void signTxGovernanceVotingRegistration_handleDelegationAPDU(const uint8_ TRACE_BUFFER(wireDataBuffer, wireDataSize); read_view_t view = make_read_view(wireDataBuffer, wireDataBuffer + wireDataSize); - _parseVotingKey(&view); + _parseVoteKey(&view); subctx->stateData.delegation.weight = parse_u4be(&view); - TRACE("Governance voting registration delegation weight:"); + TRACE("CIP-36 voting registration delegation weight:"); TRACE_UINT64(subctx->stateData.delegation.weight); VALIDATE(view_remainingSize(&view) == 0, ERR_INVALID_DATA); } - security_policy_t policy = _determineVotingKeyPolicy(); + security_policy_t policy = _determineVoteKeyPolicy(); TRACE("Policy: %d", (int) policy); ENSURE_NOT_DENIED(policy); @@ -434,20 +434,20 @@ static void signTxGovernanceVotingRegistration_handleDelegationAPDU(const uint8_ switch (subctx->stateData.delegation.type) { case DELEGATION_KEY: { - auxDataHashBuilder_governanceVotingRegistration_addDelegation( + auxDataHashBuilder_cVoteRegistration_addDelegation( auxDataHashBuilder, - subctx->stateData.delegation.votingPubKey, GOVERNANCE_VOTING_PUBLIC_KEY_LENGTH, + subctx->stateData.delegation.votePubKey, CVOTE_PUBLIC_KEY_LENGTH, subctx->stateData.delegation.weight ); break; } case DELEGATION_PATH: { - extendedPublicKey_t extVotingPubKey; - deriveExtendedPublicKey(&subctx->stateData.delegation.votingPubKeyPath, &extVotingPubKey); - auxDataHashBuilder_governanceVotingRegistration_addDelegation( + extendedPublicKey_t extVotePubKey; + deriveExtendedPublicKey(&subctx->stateData.delegation.votePubKeyPath, &extVotePubKey); + auxDataHashBuilder_cVoteRegistration_addDelegation( auxDataHashBuilder, - extVotingPubKey.pubKey, SIZEOF(extVotingPubKey.pubKey), + extVotePubKey.pubKey, SIZEOF(extVotePubKey.pubKey), subctx->stateData.delegation.weight ); break; @@ -463,7 +463,7 @@ static void signTxGovernanceVotingRegistration_handleDelegationAPDU(const uint8_ switch (policy) { #define CASE(POLICY, UI_STEP) case POLICY: {subctx->ui_step=UI_STEP; break;} CASE(POLICY_PROMPT_WARN_UNUSUAL, HANDLE_DELEGATION_STEP_WARNING); - CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_DELEGATION_STEP_VOTING_KEY); + CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_DELEGATION_STEP_VOTE_KEY); CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_DELEGATION_STEP_RESPOND); #undef CASE default: @@ -471,7 +471,7 @@ static void signTxGovernanceVotingRegistration_handleDelegationAPDU(const uint8_ } } - signTxGovernanceVotingRegistration_handleDelegation_ui_runStep(); + signTxCVoteRegistration_handleDelegation_ui_runStep(); } // ============================== STAKING KEY ============================== @@ -483,12 +483,12 @@ enum { HANDLE_STAKING_KEY_STEP_INVALID, }; -static void signTxGovernanceVotingRegistration_handleStakingKey_ui_runStep() +static void signTxCVoteRegistration_handleStakingKey_ui_runStep() { - governance_voting_registration_context_t* subctx = accessSubContext(); + cvote_registration_context_t* subctx = accessSubContext(); TRACE("UI step %d", subctx->ui_step); TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTxGovernanceVotingRegistration_handleStakingKey_ui_runStep; + ui_callback_fn_t* this_fn = signTxCVoteRegistration_handleStakingKey_ui_runStep; UI_STEP_BEGIN(subctx->ui_step, this_fn); @@ -513,15 +513,15 @@ static void signTxGovernanceVotingRegistration_handleStakingKey_ui_runStep() } __noinline_due_to_stack__ -static void signTxGovernanceVotingRegistration_handleStakingKeyAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) +static void signTxCVoteRegistration_handleStakingKeyAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) { TRACE_STACK_USAGE(); { // sanity checks - CHECK_STATE(STATE_GOVERNANCE_VOTING_REGISTRATION_STAKING_KEY); + CHECK_STATE(STATE_CVOTE_REGISTRATION_STAKING_KEY); ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); } - governance_voting_registration_context_t* subctx = accessSubContext(); + cvote_registration_context_t* subctx = accessSubContext(); { explicit_bzero(&subctx->stakingKeyPath, SIZEOF(subctx->stakingKeyPath)); } @@ -540,7 +540,7 @@ static void signTxGovernanceVotingRegistration_handleStakingKeyAPDU(const uint8_ } - security_policy_t policy = policyForGovernanceVotingRegistrationStakingKey( + security_policy_t policy = policyForCVoteRegistrationStakingKey( &subctx->stakingKeyPath ); TRACE("Policy: %d", (int) policy); @@ -549,7 +549,7 @@ static void signTxGovernanceVotingRegistration_handleStakingKeyAPDU(const uint8_ { extendedPublicKey_t extStakingPubKey; deriveExtendedPublicKey(&subctx->stakingKeyPath, &extStakingPubKey); - auxDataHashBuilder_governanceVotingRegistration_addStakingKey( + auxDataHashBuilder_cVoteRegistration_addStakingKey( &AUX_DATA_CTX->auxDataHashBuilder, extStakingPubKey.pubKey, SIZEOF(extStakingPubKey.pubKey) ); } @@ -567,7 +567,7 @@ static void signTxGovernanceVotingRegistration_handleStakingKeyAPDU(const uint8_ } } - signTxGovernanceVotingRegistration_handleStakingKey_ui_runStep(); + signTxCVoteRegistration_handleStakingKey_ui_runStep(); } // ============================== VOTING REWARDS ADDRESS ============================== @@ -607,33 +607,33 @@ static size_t _destinationToAddress( } enum { - HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_WARNING = 8500, - HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS, - HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_RESPOND, - HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_INVALID + HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_WARNING = 8500, + HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS, + HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_RESPOND, + HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_INVALID }; __noinline_due_to_stack__ -static void signTxGovernanceVotingRegistration_handleVotingRewardsAddress_ui_runStep() +static void signTxCVoteRegistration_handlePaymentAddress_ui_runStep() { - governance_voting_registration_context_t* subctx = accessSubContext(); + cvote_registration_context_t* subctx = accessSubContext(); TRACE("UI step %d", subctx->ui_step); TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTxGovernanceVotingRegistration_handleVotingRewardsAddress_ui_runStep; + ui_callback_fn_t* this_fn = signTxCVoteRegistration_handlePaymentAddress_ui_runStep; UI_STEP_BEGIN(subctx->ui_step, this_fn); - UI_STEP(HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_WARNING) { + UI_STEP(HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_WARNING) { ui_displayPaginatedText( "Unusual request", "Proceed with care", this_fn ); } - UI_STEP(HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS) { + UI_STEP(HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS) { uint8_t addressBuffer[MAX_ADDRESS_SIZE] = {0}; size_t addressSize = _destinationToAddress( - &subctx->stateData.rewardDestination, + &subctx->stateData.paymentDestination, addressBuffer, SIZEOF(addressBuffer) ); @@ -644,27 +644,27 @@ static void signTxGovernanceVotingRegistration_handleVotingRewardsAddress_ui_run this_fn ); } - UI_STEP(HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_RESPOND) { + UI_STEP(HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_RESPOND) { respondSuccessEmptyMsg(); advanceState(); } - UI_STEP_END(HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_INVALID); + UI_STEP_END(HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_INVALID); } __noinline_due_to_stack__ -static void signTxGovernanceVotingRegistration_handleVotingRewardsAddressAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) +static void signTxCVoteRegistration_handlePaymentAddressAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) { { // safety checks - CHECK_STATE(STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_REWARDS_ADDRESS); + CHECK_STATE(STATE_CVOTE_REGISTRATION_PAYMENT_ADDRESS); ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); } - governance_voting_registration_context_t* subctx = accessSubContext(); + cvote_registration_context_t* subctx = accessSubContext(); { explicit_bzero( - &subctx->stateData.rewardDestination, - SIZEOF(subctx->stateData.rewardDestination) + &subctx->stateData.paymentDestination, + SIZEOF(subctx->stateData.paymentDestination) ); } { @@ -672,13 +672,13 @@ static void signTxGovernanceVotingRegistration_handleVotingRewardsAddressAPDU(co read_view_t view = make_read_view(wireDataBuffer, wireDataBuffer + wireDataSize); - view_parseDestination(&view, &subctx->stateData.rewardDestination); + view_parseDestination(&view, &subctx->stateData.paymentDestination); VALIDATE(view_remainingSize(&view) == 0, ERR_INVALID_DATA); } - security_policy_t policy = policyForGovernanceVotingRegistrationVotingRewardsDestination( - &subctx->stateData.rewardDestination, + security_policy_t policy = policyForCVoteRegistrationPaymentDestination( + &subctx->stateData.paymentDestination, commonTxData->networkId ); TRACE("Policy: %d", (int) policy); @@ -687,11 +687,11 @@ static void signTxGovernanceVotingRegistration_handleVotingRewardsAddressAPDU(co { uint8_t addressBuffer[MAX_ADDRESS_SIZE] = {0}; size_t addressSize = _destinationToAddress( - &subctx->stateData.rewardDestination, + &subctx->stateData.paymentDestination, addressBuffer, SIZEOF(addressBuffer) ); - auxDataHashBuilder_governanceVotingRegistration_addVotingRewardsAddress( + auxDataHashBuilder_cVoteRegistration_addPaymentAddress( &AUX_DATA_CTX->auxDataHashBuilder, addressBuffer, addressSize ); } @@ -700,15 +700,15 @@ static void signTxGovernanceVotingRegistration_handleVotingRewardsAddressAPDU(co // select UI steps switch (policy) { #define CASE(POLICY, UI_STEP) case POLICY: {subctx->ui_step=UI_STEP; break;} - CASE(POLICY_PROMPT_WARN_UNUSUAL, HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_WARNING); - CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS); - CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_VOTING_REWARDS_ADDRESS_PARAMS_STEP_RESPOND); + CASE(POLICY_PROMPT_WARN_UNUSUAL, HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_WARNING); + CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS); + CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_RESPOND); #undef CASE default: THROW(ERR_NOT_IMPLEMENTED); } - signTxGovernanceVotingRegistration_handleVotingRewardsAddress_ui_runStep(); + signTxCVoteRegistration_handlePaymentAddress_ui_runStep(); } } @@ -720,12 +720,12 @@ enum { HANDLE_NONCE_STEP_INVALID, }; -static void signTxGovernanceVotingRegistration_handleNonce_ui_runStep() +static void signTxCVoteRegistration_handleNonce_ui_runStep() { - governance_voting_registration_context_t* subctx = accessSubContext(); + cvote_registration_context_t* subctx = accessSubContext(); TRACE("UI step %d", subctx->ui_step); TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTxGovernanceVotingRegistration_handleNonce_ui_runStep; + ui_callback_fn_t* this_fn = signTxCVoteRegistration_handleNonce_ui_runStep; UI_STEP_BEGIN(subctx->ui_step, this_fn); @@ -744,15 +744,15 @@ static void signTxGovernanceVotingRegistration_handleNonce_ui_runStep() } __noinline_due_to_stack__ -static void signTxGovernanceVotingRegistration_handleNonceAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) +static void signTxCVoteRegistration_handleNonceAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) { { // sanity checks - CHECK_STATE(STATE_GOVERNANCE_VOTING_REGISTRATION_NONCE); + CHECK_STATE(STATE_CVOTE_REGISTRATION_NONCE); ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); } - governance_voting_registration_context_t* subctx = accessSubContext(); + cvote_registration_context_t* subctx = accessSubContext(); { explicit_bzero(&subctx->stateData, SIZEOF(subctx->stateData)); } @@ -761,16 +761,16 @@ static void signTxGovernanceVotingRegistration_handleNonceAPDU(const uint8_t* wi TRACE_BUFFER(wireDataBuffer, wireDataSize); VALIDATE(wireDataSize == 8, ERR_INVALID_DATA); subctx->stateData.nonce = u8be_read(wireDataBuffer); - TRACE("Governance voting registration nonce:"); + TRACE("CIP-36 voting registration nonce:"); TRACE_UINT64(subctx->stateData.nonce); } - security_policy_t policy = policyForGovernanceVotingRegistrationNonce(); + security_policy_t policy = policyForCVoteRegistrationNonce(); TRACE("Policy: %d", (int) policy); ENSURE_NOT_DENIED(policy); { - auxDataHashBuilder_governanceVotingRegistration_addNonce(&AUX_DATA_CTX->auxDataHashBuilder, subctx->stateData.nonce); + auxDataHashBuilder_cVoteRegistration_addNonce(&AUX_DATA_CTX->auxDataHashBuilder, subctx->stateData.nonce); } { @@ -785,7 +785,7 @@ static void signTxGovernanceVotingRegistration_handleNonceAPDU(const uint8_t* wi } } - signTxGovernanceVotingRegistration_handleNonce_ui_runStep(); + signTxCVoteRegistration_handleNonce_ui_runStep(); } // ============================== VOTING PURPOSE ============================== @@ -796,12 +796,12 @@ enum { HANDLE_VOTING_PURPOSE_STEP_INVALID, }; -static void signTxGovernanceVotingRegistration_handleVotingPurpose_ui_runStep() +static void signTxCVoteRegistration_handleVotingPurpose_ui_runStep() { - governance_voting_registration_context_t* subctx = accessSubContext(); + cvote_registration_context_t* subctx = accessSubContext(); TRACE("UI step %d", subctx->ui_step); TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTxGovernanceVotingRegistration_handleVotingPurpose_ui_runStep; + ui_callback_fn_t* this_fn = signTxCVoteRegistration_handleVotingPurpose_ui_runStep; UI_STEP_BEGIN(subctx->ui_step, this_fn); @@ -822,14 +822,14 @@ static void signTxGovernanceVotingRegistration_handleVotingPurpose_ui_runStep() #define DEFAULT_VOTING_PURPOSE (0) __noinline_due_to_stack__ -static void signTxGovernanceVotingRegistration_handleVotingPurposeAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) +static void signTxCVoteRegistration_handleVotingPurposeAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) { { - CHECK_STATE(STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_PURPOSE); + CHECK_STATE(STATE_CVOTE_REGISTRATION_VOTING_PURPOSE); ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); } - governance_voting_registration_context_t* subctx = accessSubContext(); + cvote_registration_context_t* subctx = accessSubContext(); { explicit_bzero(&subctx->stateData, SIZEOF(subctx->stateData)); } @@ -865,12 +865,12 @@ static void signTxGovernanceVotingRegistration_handleVotingPurposeAPDU(const uin return; } - security_policy_t policy = policyForGovernanceVotingRegistrationVotingPurpose(); + security_policy_t policy = policyForCVoteRegistrationVotingPurpose(); TRACE("Policy: %d", (int) policy); ENSURE_NOT_DENIED(policy); { - auxDataHashBuilder_governanceVotingRegistration_addVotingPurpose( + auxDataHashBuilder_cVoteRegistration_addVotingPurpose( &AUX_DATA_CTX->auxDataHashBuilder, subctx->stateData.votingPurpose ); @@ -887,7 +887,7 @@ static void signTxGovernanceVotingRegistration_handleVotingPurposeAPDU(const uin } } - signTxGovernanceVotingRegistration_handleVotingPurpose_ui_runStep(); + signTxCVoteRegistration_handleVotingPurpose_ui_runStep(); } @@ -900,12 +900,12 @@ enum { HANDLE_CONFIRM_STEP_INVALID, }; -static void signTxGovernanceVotingRegistration_handleConfirm_ui_runStep() +static void signTxCVoteRegistration_handleConfirm_ui_runStep() { - governance_voting_registration_context_t* subctx = accessSubContext(); + cvote_registration_context_t* subctx = accessSubContext(); TRACE("UI step %d", subctx->ui_step); TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTxGovernanceVotingRegistration_handleConfirm_ui_runStep; + ui_callback_fn_t* this_fn = signTxCVoteRegistration_handleConfirm_ui_runStep; UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM) { @@ -938,7 +938,7 @@ static void signTxGovernanceVotingRegistration_handleConfirm_ui_runStep() STATIC_ASSERT(SIZEOF(subctx->auxDataHash) == AUX_DATA_HASH_LENGTH, "Wrong aux data hash length"); memmove(wireResponse.auxDataHash, subctx->auxDataHash, AUX_DATA_HASH_LENGTH); - STATIC_ASSERT(SIZEOF(subctx->stateData.registrationSignature) == ED25519_SIGNATURE_LENGTH, "Wrong governance voting registration signature length"); + STATIC_ASSERT(SIZEOF(subctx->stateData.registrationSignature) == ED25519_SIGNATURE_LENGTH, "Wrong CIP-36 voting registration signature length"); memmove(wireResponse.signature, subctx->stateData.registrationSignature, ED25519_SIGNATURE_LENGTH); io_send_buf(SUCCESS, (uint8_t*) &wireResponse, SIZEOF(wireResponse)); @@ -948,15 +948,15 @@ static void signTxGovernanceVotingRegistration_handleConfirm_ui_runStep() } __noinline_due_to_stack__ -static void signTxGovernanceVotingRegistration_handleConfirmAPDU(const uint8_t* wireDataBuffer MARK_UNUSED, size_t wireDataSize) +static void signTxCVoteRegistration_handleConfirmAPDU(const uint8_t* wireDataBuffer MARK_UNUSED, size_t wireDataSize) { { //sanity checks - CHECK_STATE(STATE_GOVERNANCE_VOTING_REGISTRATION_CONFIRM); + CHECK_STATE(STATE_CVOTE_REGISTRATION_CONFIRM); ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); } - governance_voting_registration_context_t* subctx = accessSubContext(); + cvote_registration_context_t* subctx = accessSubContext(); { explicit_bzero(&subctx->stateData, SIZEOF(subctx->stateData)); } @@ -966,23 +966,23 @@ static void signTxGovernanceVotingRegistration_handleConfirmAPDU(const uint8_t* VALIDATE(wireDataSize == 0, ERR_INVALID_DATA); } - security_policy_t policy = policyForGovernanceVotingRegistrationConfirm(); + security_policy_t policy = policyForCVoteRegistrationConfirm(); TRACE("Policy: %d", (int) policy); ENSURE_NOT_DENIED(policy); { aux_data_hash_builder_t* auxDataHashBuilder = &AUX_DATA_CTX->auxDataHashBuilder; { - uint8_t votingPayloadHashBuffer[GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_HASH_LENGTH] = {0}; - auxDataHashBuilder_governanceVotingRegistration_finalizePayload(auxDataHashBuilder, votingPayloadHashBuffer, AUX_DATA_HASH_LENGTH); - getGovernanceVotingRegistrationSignature( + uint8_t payloadHashBuffer[CVOTE_REGISTRATION_PAYLOAD_HASH_LENGTH] = {0}; + auxDataHashBuilder_cVoteRegistration_finalizePayload(auxDataHashBuilder, payloadHashBuffer, AUX_DATA_HASH_LENGTH); + getCVoteRegistrationSignature( &subctx->stakingKeyPath, - votingPayloadHashBuffer, GOVERNANCE_VOTING_REGISTRATION_PAYLOAD_HASH_LENGTH, + payloadHashBuffer, CVOTE_REGISTRATION_PAYLOAD_HASH_LENGTH, subctx->stateData.registrationSignature, ED25519_SIGNATURE_LENGTH ); } - auxDataHashBuilder_governanceVotingRegistration_addSignature(auxDataHashBuilder, subctx->stateData.registrationSignature, ED25519_SIGNATURE_LENGTH); - auxDataHashBuilder_governanceVotingRegistration_addAuxiliaryScripts(auxDataHashBuilder); + auxDataHashBuilder_cVoteRegistration_addSignature(auxDataHashBuilder, subctx->stateData.registrationSignature, ED25519_SIGNATURE_LENGTH); + auxDataHashBuilder_cVoteRegistration_addAuxiliaryScripts(auxDataHashBuilder); auxDataHashBuilder_finalize(auxDataHashBuilder, subctx->auxDataHash, AUX_DATA_HASH_LENGTH); } @@ -999,7 +999,7 @@ static void signTxGovernanceVotingRegistration_handleConfirmAPDU(const uint8_t* } } - signTxGovernanceVotingRegistration_handleConfirm_ui_runStep(); + signTxCVoteRegistration_handleConfirm_ui_runStep(); } @@ -1007,23 +1007,23 @@ static void signTxGovernanceVotingRegistration_handleConfirmAPDU(const uint8_t* enum { APDU_INSTRUCTION_INIT = 0x36, - APDU_INSTRUCTION_VOTING_KEY = 0x30, + APDU_INSTRUCTION_VOTE_KEY = 0x30, APDU_INSTRUCTION_DELEGATION = 0x37, APDU_INSTRUCTION_STAKING_KEY = 0x31, - APDU_INSTRUCTION_VOTING_REWARDS_ADDRESS = 0x32, + APDU_INSTRUCTION_PAYMENT_ADDRESS = 0x32, APDU_INSTRUCTION_NONCE = 0x33, APDU_INSTRUCTION_VOTING_PURPOSE = 0x35, APDU_INSTRUCTION_CONFIRM = 0x34 }; -bool signTxGovernanceVotingRegistration_isValidInstruction(uint8_t p2) +bool signTxCVoteRegistration_isValidInstruction(uint8_t p2) { switch (p2) { case APDU_INSTRUCTION_INIT: - case APDU_INSTRUCTION_VOTING_KEY: + case APDU_INSTRUCTION_VOTE_KEY: case APDU_INSTRUCTION_DELEGATION: case APDU_INSTRUCTION_STAKING_KEY: - case APDU_INSTRUCTION_VOTING_REWARDS_ADDRESS: + case APDU_INSTRUCTION_PAYMENT_ADDRESS: case APDU_INSTRUCTION_NONCE: case APDU_INSTRUCTION_VOTING_PURPOSE: case APDU_INSTRUCTION_CONFIRM: @@ -1034,41 +1034,41 @@ bool signTxGovernanceVotingRegistration_isValidInstruction(uint8_t p2) } } -void signTxGovernanceVotingRegistration_handleAPDU(uint8_t p2, const uint8_t* wireDataBuffer, size_t wireDataSize) +void signTxCVoteRegistration_handleAPDU(uint8_t p2, const uint8_t* wireDataBuffer, size_t wireDataSize) { ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA); switch (p2) { case APDU_INSTRUCTION_INIT: - signTxGovernanceVotingRegistration_handleInitAPDU(wireDataBuffer, wireDataSize); + signTxCVoteRegistration_handleInitAPDU(wireDataBuffer, wireDataSize); break; - case APDU_INSTRUCTION_VOTING_KEY: - signTxGovernanceVotingRegistration_handleVotingKeyAPDU(wireDataBuffer, wireDataSize); + case APDU_INSTRUCTION_VOTE_KEY: + signTxCVoteRegistration_handleVoteKeyAPDU(wireDataBuffer, wireDataSize); break; case APDU_INSTRUCTION_DELEGATION: - signTxGovernanceVotingRegistration_handleDelegationAPDU(wireDataBuffer, wireDataSize); + signTxCVoteRegistration_handleDelegationAPDU(wireDataBuffer, wireDataSize); break; case APDU_INSTRUCTION_STAKING_KEY: - signTxGovernanceVotingRegistration_handleStakingKeyAPDU(wireDataBuffer, wireDataSize); + signTxCVoteRegistration_handleStakingKeyAPDU(wireDataBuffer, wireDataSize); break; - case APDU_INSTRUCTION_VOTING_REWARDS_ADDRESS: - signTxGovernanceVotingRegistration_handleVotingRewardsAddressAPDU(wireDataBuffer, wireDataSize); + case APDU_INSTRUCTION_PAYMENT_ADDRESS: + signTxCVoteRegistration_handlePaymentAddressAPDU(wireDataBuffer, wireDataSize); break; case APDU_INSTRUCTION_NONCE: - signTxGovernanceVotingRegistration_handleNonceAPDU(wireDataBuffer, wireDataSize); + signTxCVoteRegistration_handleNonceAPDU(wireDataBuffer, wireDataSize); break; case APDU_INSTRUCTION_VOTING_PURPOSE: - signTxGovernanceVotingRegistration_handleVotingPurposeAPDU(wireDataBuffer, wireDataSize); + signTxCVoteRegistration_handleVotingPurposeAPDU(wireDataBuffer, wireDataSize); break; case APDU_INSTRUCTION_CONFIRM: - signTxGovernanceVotingRegistration_handleConfirmAPDU(wireDataBuffer, wireDataSize); + signTxCVoteRegistration_handleConfirmAPDU(wireDataBuffer, wireDataSize); break; default: diff --git a/src/signTxCVoteRegistration.h b/src/signTxCVoteRegistration.h new file mode 100644 index 00000000..1d96dc5d --- /dev/null +++ b/src/signTxCVoteRegistration.h @@ -0,0 +1,70 @@ +#ifndef H_CARDANO_APP_SIGN_TX_CVOTE_REGISTRATION +#define H_CARDANO_APP_SIGN_TX_CVOTE_REGISTRATION + +#include "common.h" +#include "cardano.h" +#include "auxDataHashBuilder.h" +#include "txHashBuilder.h" +#include "addressUtilsShelley.h" + + +#define CVOTE_PUBLIC_KEY_LENGTH 32 + +// SIGN_STAGE_AUX_DATA = 24 +// AUX_DATA_TYPE_CVOTE_REGISTRATION = 1 +typedef enum { + STATE_CVOTE_REGISTRATION_INIT = 2410, + STATE_CVOTE_REGISTRATION_VOTE_KEY = 2411, + STATE_CVOTE_REGISTRATION_DELEGATIONS = 2412, + STATE_CVOTE_REGISTRATION_STAKING_KEY = 2413, + STATE_CVOTE_REGISTRATION_PAYMENT_ADDRESS = 2414, + STATE_CVOTE_REGISTRATION_NONCE = 2415, + STATE_CVOTE_REGISTRATION_VOTING_PURPOSE = 2416, + STATE_CVOTE_REGISTRATION_CONFIRM = 2417, + STATE_CVOTE_REGISTRATION_FINISHED = 2418 +} sign_tx_cvote_registration_state_t; + +typedef enum { + DELEGATION_KEY = 1, + DELEGATION_PATH = 2 +} cvote_delegation_type_t; + +typedef struct { + sign_tx_cvote_registration_state_t state; + int ui_step; + + cvote_registration_format_t format; + uint16_t numDelegations; // if 0, only a single key expected, no delegations + uint16_t currentDelegation; + /* + * Staking key path kept outside of stateData to produce the CIP-36 voting registration + * signature at the end of the flow without re-requesting the staking key path + * (with the undesired side-effect of allowing signing with a different key than included + * in the registration payload) + */ + bip44_path_t stakingKeyPath; + + uint8_t auxDataHash[AUX_DATA_HASH_LENGTH]; + + union { + struct { + cvote_delegation_type_t type; + bip44_path_t votePubKeyPath; + uint8_t votePubKey[CVOTE_PUBLIC_KEY_LENGTH]; + uint32_t weight; + } delegation; + tx_output_destination_storage_t paymentDestination; + uint64_t nonce; + uint64_t votingPurpose; + uint8_t registrationSignature[ED25519_SIGNATURE_LENGTH]; + } stateData; +} cvote_registration_context_t; + +void signTxCVoteRegistration_init(); + +bool signTxCVoteRegistration_isValidInstruction(uint8_t p2); +void signTxCVoteRegistration_handleAPDU(uint8_t p2, const uint8_t* wireDataBuffer, size_t wireDataSize); + +bool signTxCVoteRegistration_isFinished(); + +#endif // H_CARDANO_APP_SIGN_TX_CVOTE_REGISTRATION diff --git a/src/signTxGovernanceVotingRegistration.h b/src/signTxGovernanceVotingRegistration.h deleted file mode 100644 index bd304df6..00000000 --- a/src/signTxGovernanceVotingRegistration.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef H_CARDANO_APP_SIGN_TX_GOVERNANCE_VOTING_REGISTRATION -#define H_CARDANO_APP_SIGN_TX_GOVERNANCE_VOTING_REGISTRATION - -#include "common.h" -#include "cardano.h" -#include "auxDataHashBuilder.h" -#include "txHashBuilder.h" -#include "addressUtilsShelley.h" - - -#define GOVERNANCE_VOTING_PUBLIC_KEY_LENGTH 32 - -// SIGN_STAGE_AUX_DATA = 24 -// AUX_DATA_TYPE_CIP36_REGISTRATION = 1 -typedef enum { - STATE_GOVERNANCE_VOTING_REGISTRATION_INIT = 2410, - STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_KEY = 2411, - STATE_GOVERNANCE_VOTING_REGISTRATION_DELEGATIONS = 2412, - STATE_GOVERNANCE_VOTING_REGISTRATION_STAKING_KEY = 2413, - STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_REWARDS_ADDRESS = 2414, - STATE_GOVERNANCE_VOTING_REGISTRATION_NONCE = 2415, - STATE_GOVERNANCE_VOTING_REGISTRATION_VOTING_PURPOSE = 2416, - STATE_GOVERNANCE_VOTING_REGISTRATION_CONFIRM = 2417, - STATE_GOVERNANCE_VOTING_REGISTRATION_FINISHED = 2418 -} sign_tx_governance_voting_registration_state_t; - -typedef enum { - DELEGATION_KEY = 1, - DELEGATION_PATH = 2 -} governance_voting_delegation_type_t; - -typedef struct { - sign_tx_governance_voting_registration_state_t state; - int ui_step; - - governance_voting_registration_format_t format; - uint16_t numDelegations; // if 0, only a single key expected, no delegations - uint16_t currentDelegation; - /* - * Staking key path kept outside of stateData to produce the governance voting registration - * signature at the end of the flow without re-requesting the staking key path - * (with the undesired side-effect of allowing signing with a different key than included - * in the registration payload) - */ - bip44_path_t stakingKeyPath; - - uint8_t auxDataHash[AUX_DATA_HASH_LENGTH]; - - union { - struct { - governance_voting_delegation_type_t type; - bip44_path_t votingPubKeyPath; - uint8_t votingPubKey[GOVERNANCE_VOTING_PUBLIC_KEY_LENGTH]; - uint32_t weight; - } delegation; - tx_output_destination_storage_t rewardDestination; - uint64_t nonce; - uint64_t votingPurpose; - uint8_t registrationSignature[ED25519_SIGNATURE_LENGTH]; - } stateData; -} governance_voting_registration_context_t; - -void signTxGovernanceVotingRegistration_init(); - -bool signTxGovernanceVotingRegistration_isValidInstruction(uint8_t p2); -void signTxGovernanceVotingRegistration_handleAPDU(uint8_t p2, const uint8_t* wireDataBuffer, size_t wireDataSize); - -bool signTxGovernanceVotingRegistration_isFinished(); - -#endif // H_CARDANO_APP_SIGN_TX_GOVERNANCE_VOTING_REGISTRATION diff --git a/src/signTxMint.c b/src/signTxMint.c index c996b7d8..cbd3b325 100644 --- a/src/signTxMint.c +++ b/src/signTxMint.c @@ -202,7 +202,7 @@ static void signTxMint_handleAssetGroupAPDU(const uint8_t* wireDataBuffer, size_ } { - // add tokengroup to tx + // add token group to tx TRACE("Adding token group hash to tx hash"); txHashBuilder_addMint_tokenGroup( &BODY_CTX->txHashBuilder, @@ -312,7 +312,7 @@ static void signTxMint_handleTokenAPDU(const uint8_t* wireDataBuffer, size_t wir } { - // add tokengroup to tx + // add token group to tx TRACE("Adding token group hash to tx hash"); txHashBuilder_addMint_token( &BODY_CTX->txHashBuilder, diff --git a/src/signTxOutput.c b/src/signTxOutput.c index 6f09ae2c..7ebb10f6 100644 --- a/src/signTxOutput.c +++ b/src/signTxOutput.c @@ -571,7 +571,7 @@ static void handleCollateralOutput_addressBytes() .includeRefScript = subctx->includeRefScript, }; - // TODO maybe restric to specific address types? we don't support datum in coll ret outputs + // TODO maybe restrict to specific address types? we don't support datum in coll ret outputs security_policy_t policy = policyForSignTxCollateralOutputAddressBytes( &output, commonTxData->txSigningMode, @@ -753,7 +753,7 @@ static void handleAssetGroupAPDU(const uint8_t* wireDataBuffer, size_t wireDataS VALIDATE(view_remainingSize(&view) == 0, ERR_INVALID_DATA); } { - // add tokengroup to tx + // add token group to tx TRACE("Adding token group hash to tx hash"); switch (ctx->stage) { @@ -871,7 +871,7 @@ static void handleTokenAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) VALIDATE(view_remainingSize(&view) == 0, ERR_INVALID_DATA); } { - // add tokengroup to tx + // add token group to tx TRACE("Adding token group hash to tx hash"); switch (ctx->stage) { diff --git a/src/signTxPoolRegistration.c b/src/signTxPoolRegistration.c index f641e7f5..78635b37 100644 --- a/src/signTxPoolRegistration.c +++ b/src/signTxPoolRegistration.c @@ -1276,7 +1276,7 @@ static void signTxPoolRegistration_handlePoolMetadataAPDU(const uint8_t* wireDat { md->urlSize = view_remainingSize(&view); VALIDATE(md->urlSize <= POOL_METADATA_URL_LENGTH_MAX, ERR_INVALID_DATA); - STATIC_ASSERT(SIZEOF(md->url) >= POOL_METADATA_URL_LENGTH_MAX, "wrong pool metada url size"); + STATIC_ASSERT(SIZEOF(md->url) >= POOL_METADATA_URL_LENGTH_MAX, "wrong pool metadata url size"); view_parseBuffer(md->url, &view, md->urlSize); // whitespace not allowed @@ -1334,7 +1334,7 @@ static void signTxPoolRegistration_handleConfirm_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); - // we display potencially suspicious facts about the certificate + // we display potentially suspicious facts about the certificate // that have not been explicitly shown to the user before: // missing owners or relays UI_STEP(HANDLE_CONFIRM_STEP_FINAL_NO_OWNERS) { diff --git a/src/signTxUtils.c b/src/signTxUtils.c index f879be47..daca4896 100644 --- a/src/signTxUtils.c +++ b/src/signTxUtils.c @@ -46,7 +46,8 @@ bool violatesSingleAccountOrStoreIt(const bip44_path_t* path) return false; } -void view_parseDestination(read_view_t* view, tx_output_destination_storage_t* destination) { +void view_parseDestination(read_view_t* view, tx_output_destination_storage_t* destination) +{ destination->type = parse_u1be(view); TRACE("Destination type %d", (int) destination->type); diff --git a/src/state.h b/src/state.h index 1d71bb90..8ca7f18a 100644 --- a/src/state.h +++ b/src/state.h @@ -7,7 +7,7 @@ #include "deriveNativeScriptHash.h" #include "signTx.h" #include "signOpCert.h" -#include "signGovernanceVote.h" +#include "signCVote.h" typedef union { @@ -17,7 +17,7 @@ typedef union { ins_derive_native_script_hash_context_t deriveNativeScriptHashContext; ins_sign_tx_context_t signTxContext; ins_sign_op_cert_context_t signOpCertContext; - ins_sign_governance_vote_context_t signGovernanceVoteContext; + ins_sign_cvote_context_t signCVoteContext; } instructionState_t; // Note(instructions are uint8_t but we have a special INS_NONE value diff --git a/src/textUtils.c b/src/textUtils.c index abbd1bf4..1eac4c93 100644 --- a/src/textUtils.c +++ b/src/textUtils.c @@ -301,6 +301,7 @@ bool str_isAllowedDnsName(const uint8_t* buffer, size_t bufferSize) #ifdef DEVEL +/* cspell:disable-next-line */ // converts a text to bytes (suitable for CBORization) and validates if chars are allowed size_t str_textToBuffer(const char* text, uint8_t* buffer, size_t bufferSize) { diff --git a/src/tokens_test.c b/src/tokens_test.c index 731e7773..c78be646 100644 --- a/src/tokens_test.c +++ b/src/tokens_test.c @@ -72,15 +72,15 @@ typedef struct { char expectedMint[50]; } token_testcase_t; -const token_testcase_t tokenTestcases[] = { +const token_testcase_t tokenTestCases[] = { { { 0x94, 0xcb, 0xb4, 0xfc, 0xbc, 0xaa, 0x29, 0x75, 0x77, 0x9f, 0x27, 0x3b, 0x26, 0x3e, 0xb3, 0xb5, 0xf2, 0x4a, 0x99, 0x51, 0xe4, 0x46, 0xd6, 0xdc, 0x4c, 0x13, 0x58, 0x64 }, { 0x52, 0x45, 0x56, 0x55 }, 4, 234, - "0.00000234 REVU", + "0.00000234 REVU", // cspell:disable-line -234, - "-0.00000234 REVU" + "-0.00000234 REVU" // cspell:disable-line }, { // no decimal places in our table @@ -96,26 +96,26 @@ const token_testcase_t tokenTestcases[] = { void test_decimalPlaces() { - for (size_t i = 0; i < ARRAY_LEN(tokenTestcases); i++) { + for (size_t i = 0; i < ARRAY_LEN(tokenTestCases); i++) { char tokenAmountStr[60]; token_group_t group; - memcpy(group.policyId, tokenTestcases[i].policyId, MINTING_POLICY_ID_SIZE); + memcpy(group.policyId, tokenTestCases[i].policyId, MINTING_POLICY_ID_SIZE); str_formatTokenAmountOutput( &group, - tokenTestcases[i].assetNameBytes, tokenTestcases[i].assetNameSize, - tokenTestcases[i].amountOutput, + tokenTestCases[i].assetNameBytes, tokenTestCases[i].assetNameSize, + tokenTestCases[i].amountOutput, tokenAmountStr, SIZEOF(tokenAmountStr) ); - EXPECT_EQ(strcmp(tokenAmountStr, tokenTestcases[i].expectedOutput), 0); + EXPECT_EQ(strcmp(tokenAmountStr, tokenTestCases[i].expectedOutput), 0); str_formatTokenAmountMint( &group, - tokenTestcases[i].assetNameBytes, tokenTestcases[i].assetNameSize, - tokenTestcases[i].amountMint, + tokenTestCases[i].assetNameBytes, tokenTestCases[i].assetNameSize, + tokenTestCases[i].amountMint, tokenAmountStr, SIZEOF(tokenAmountStr) ); - EXPECT_EQ(strcmp(tokenAmountStr, tokenTestcases[i].expectedMint), 0); + EXPECT_EQ(strcmp(tokenAmountStr, tokenTestCases[i].expectedMint), 0); } } diff --git a/src/txHashBuilder.c b/src/txHashBuilder.c index 0dc11251..23d198d3 100644 --- a/src/txHashBuilder.c +++ b/src/txHashBuilder.c @@ -432,7 +432,7 @@ static void addTokenGroup( { // Bytes[policyId] // Map(numTokens)[ - // // entries added later { * asset_name => auint } + // // entries added later { * asset_name => uint } // ] { BUILDER_APPEND_CBOR(CBOR_TYPE_BYTES, policyIdSize); @@ -474,7 +474,7 @@ static void addToken( ASSERT(assetNameSize <= ASSET_NAME_SIZE_MAX); { // add a map entry: - // Bytes[assetname] + // Bytes[asset_name] // Unsigned[Amount] { BUILDER_APPEND_CBOR(CBOR_TYPE_BYTES, assetNameSize); diff --git a/src/txHashBuilder_test.c b/src/txHashBuilder_test.c index 5b76abca..1a0f0a8a 100644 --- a/src/txHashBuilder_test.c +++ b/src/txHashBuilder_test.c @@ -349,7 +349,7 @@ static void addPoolRegistrationCertificate(tx_hash_builder_t* builder) pool_relay_t relay1; relay1.format = 1; relay1.port.isNull = true; - // a valid DNS AAAA record, since dnsName actually is suppposed to be an A or AAAA record + // a valid DNS AAAA record, since dnsName actually is supposed to be an A or AAAA record const char* dnsName = "AAAA 2400:cb00:2049:1::a29f:1804"; relay1.dnsNameSize = str_textToBuffer(dnsName, relay1.dnsName, SIZEOF(relay1.dnsName)); txHashBuilder_addPoolRegistrationCertificate_addRelay(builder, &relay1); @@ -499,6 +499,7 @@ void run_txHashBuilder_test() } // ? 7 : auxiliary_data_hash { + /* cspell:disable-next-line */ const char auxDataHashHex[] = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"; uint8_t tmp[AUX_DATA_HASH_LENGTH] = {0}; size_t tmpSize = decode_hex(auxDataHashHex, tmp, SIZEOF(tmp)); diff --git a/tokenRegistry/convert.py b/tokenRegistry/convert.py index 8dc64a56..861c914b 100644 --- a/tokenRegistry/convert.py +++ b/tokenRegistry/convert.py @@ -6,7 +6,7 @@ # WARNING --- make sure that: # 1. token tickers are meaningful and none is "(unknown decimals)" # 2. buffers (e.g. tokenAmountStr) are big enough to hold the tickers -filename = "top100JsonList.json" +filename = "tokenList.json" registry = json.load(open(filename)) diff --git a/tokenRegistry/top100JsonList.json b/tokenRegistry/tokenList.json similarity index 98% rename from tokenRegistry/top100JsonList.json rename to tokenRegistry/tokenList.json index 2ebc8d6c..1fd16b5a 100644 --- a/tokenRegistry/top100JsonList.json +++ b/tokenRegistry/tokenList.json @@ -598,5 +598,17 @@ "name": "Indigo DAO Token", "ticker": "INDY", "decimals": 6 + }, + { + "assetSubject": "8db269c3ec630e06ae29f74bc39edd1f87c819f1056206e879a1cd61446a65644d6963726f555344", + "name": "Djed USD", + "ticker": "DJED", + "decimals": 6 + }, + { + "assetSubject": "f66d78b4a3cb3d37afa0ec36461e51ecbde00f26c8f0a68f94b6988069555344", + "name": "iUSD", + "ticker": "iUSD", + "decimals": 6 } ] diff --git a/tokenRegistry/token_data.c b/tokenRegistry/token_data.c index 2e4b6f95..34e208fe 100644 --- a/tokenRegistry/token_data.c +++ b/tokenRegistry/token_data.c @@ -97,4 +97,6 @@ { { 0x04, 0x93, 0xf4, 0x95, 0x30, 0x89, 0x8e, 0x3d, 0xfe, 0x7d, 0xc0, 0x94, 0x3d, 0x19, 0xbc, 0x1b, 0xdc, 0xb3, 0x6e, 0x10 }, 6, "C3" }, { { 0x83, 0x45, 0xbc, 0xd3, 0x13, 0x72, 0x01, 0x6d, 0x70, 0xb5, 0xb3, 0xd3, 0x3f, 0x93, 0x79, 0x9b, 0x26, 0xc4, 0xb2, 0x32 }, 4, "CLAY" }, { { 0x73, 0x88, 0x43, 0x9d, 0x27, 0xe1, 0x63, 0xeb, 0x8b, 0xd6, 0xe4, 0xff, 0x68, 0x43, 0xc8, 0xe5, 0x6b, 0xa0, 0xeb, 0x2d }, 8, "AGIX" }, -{ { 0xe1, 0xf1, 0xde, 0x48, 0x36, 0xc3, 0xed, 0xba, 0xb3, 0xee, 0x34, 0xda, 0x74, 0x96, 0x95, 0xf9, 0x83, 0x71, 0xe0, 0xff }, 6, "INDY" } +{ { 0xe1, 0xf1, 0xde, 0x48, 0x36, 0xc3, 0xed, 0xba, 0xb3, 0xee, 0x34, 0xda, 0x74, 0x96, 0x95, 0xf9, 0x83, 0x71, 0xe0, 0xff }, 6, "INDY" }, +{ { 0xa2, 0x62, 0x4d, 0xda, 0x5d, 0x49, 0x8d, 0x9e, 0x4d, 0x94, 0x42, 0xdb, 0xfa, 0x55, 0x14, 0x04, 0x0e, 0xb2, 0x16, 0xc7 }, 6, "DJED" }, +{ { 0x1e, 0xe2, 0x7e, 0xdf, 0xf4, 0x99, 0xcf, 0x88, 0xf0, 0x3a, 0x1e, 0xbc, 0x4f, 0x22, 0x6f, 0x4a, 0x4c, 0x07, 0x71, 0xde }, 6, "iUSD" } From 1a4cf8bd21a73205df65253c8c425c8318c2b4b7 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 6 Mar 2023 17:50:41 +0100 Subject: [PATCH 005/105] main.c : add missing CLOSE_TRY --- src/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main.c b/src/main.c index 8d53d731..2188fec3 100644 --- a/src/main.c +++ b/src/main.c @@ -242,9 +242,11 @@ __attribute__((section(".boot"))) int main(void) CATCH(EXCEPTION_IO_RESET) { // reset IO and UX before continuing + CLOSE_TRY; continue; } CATCH_ALL { + CLOSE_TRY; break; } FINALLY { From f4271b0c0e87e49168212388e228e7cd3ea10516 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Thu, 22 Sep 2022 10:22:24 +0200 Subject: [PATCH 006/105] Makefile: add fatstacks target --- Makefile | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index d5ee3f7e..bbf7614e 100644 --- a/Makefile +++ b/Makefile @@ -29,6 +29,8 @@ include $(BOLOS_SDK)/Makefile.defines ifeq ($(TARGET_NAME),TARGET_NANOS) ICONNAME=icon_ada_nanos.gif +else ifeq ($(TARGET_NAME),TARGET_STAX) + ICONNAME=icon_ada_stax.gif else ICONNAME=icon_ada_nanox.gif endif @@ -54,10 +56,15 @@ LDLIBS += -lm -lgcc -lc ############ DEFINES += OS_IO_SEPROXYHAL -DEFINES += HAVE_BAGL HAVE_SPRINTF HAVE_SNPRINTF_FORMAT_U +ifneq ($(TARGET_NAME),TARGET_STAX) +DEFINES += HAVE_BAGL +endif +DEFINES += HAVE_SPRINTF HAVE_SNPRINTF_FORMAT_U DEFINES += APPVERSION=\"$(APPVERSION)\" DEFINES += MAJOR_VERSION=$(APPVERSION_M) MINOR_VERSION=$(APPVERSION_N) PATCH_VERSION=$(APPVERSION_P) +DEFINES += UNUSED\(x\)=\(void\)x + ## USB HID? DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=4 IO_HID_EP_LENGTH=64 HAVE_USB_APDU @@ -70,7 +77,7 @@ DEFINES += HAVE_U2F HAVE_IO_U2F U2F_PROXY_MAGIC=\"ADA\" USB_SEGMENT_SIZE=64 DEFINES += HAVE_WEBUSB WEBUSB_URL_SIZE_B=0 WEBUSB_URL="" ## BLUETOOTH -ifeq ($(TARGET_NAME),TARGET_NANOX) +ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME),TARGET_NANOX TARGET_STAX)) DEFINES += HAVE_BLE BLE_COMMAND_TIMEOUT_MS=2000 HAVE_BLE_APDU endif @@ -83,12 +90,18 @@ DEFINES += HAVE_BOLOS_UX HAVE_UX_LEGACY COMPLIANCE_UX_160 else DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=300 DEFINES += HAVE_GLO096 +ifneq ($(TARGET_NAME),TARGET_STAX) DEFINES += HAVE_BAGL BAGL_WIDTH=128 BAGL_HEIGHT=64 +DEFINES += HAVE_UX_FLOW +endif + +ifeq ($(TARGET_NAME),TARGET_STAX) +DEFINES += NBGL_QRCODE +endif DEFINES += HAVE_BAGL_ELLIPSIS # long label truncation feature DEFINES += HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX DEFINES += HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX DEFINES += HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX -DEFINES += HAVE_UX_FLOW endif DEFINES += RESET_ON_CRASH @@ -120,11 +133,14 @@ include $(BOLOS_SDK)/Makefile.glyphs ### computed variables APP_SOURCE_PATH += src SDK_SOURCE_PATH += lib_stusb lib_stusb_impl lib_u2f + +ifneq ($(TARGET_NAME),TARGET_STAX) SDK_SOURCE_PATH += lib_ux -ifeq ($(TARGET_NAME),TARGET_NANOX) - SDK_SOURCE_PATH += lib_blewbxx lib_blewbxx_impl endif +ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME),TARGET_NANOX TARGET_STAX)) + SDK_SOURCE_PATH += lib_blewbxx lib_blewbxx_impl +endif ################ # Default rule # From 16b11844059e72e48fa6f75aea1471c6dfbee6a7 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 27 Dec 2022 15:28:04 +0100 Subject: [PATCH 007/105] add new icon and glyph --- glyphs/cardano_64.gif | Bin 0 -> 313 bytes icon_ada_stax.gif | Bin 0 -> 130 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 glyphs/cardano_64.gif create mode 100644 icon_ada_stax.gif diff --git a/glyphs/cardano_64.gif b/glyphs/cardano_64.gif new file mode 100644 index 0000000000000000000000000000000000000000..d9fd0ca43a2f1aa543bbe9acfecf4a4e2b9545a7 GIT binary patch literal 313 zcmV-90mlAENk%w1VL$*t0Du4h00030|NkNW5kqoiVRU6=Aa`kWXdp*PO;7+V00000 zKmb4h00RDukEzS;52Kv4+KVFqx!>)DAT&N@n4FEuu;>fN@=U+3#?{M~Q@pO=^-@EG z5NP}bmBicZxO6d*q$w2xMOv?hZOaMFRwv@F_gfQ|)L@yIJ%SI*qBq>kKICEhfE=%; z7Z_u=_b1r)p>lXf#07ZL_lUMrG&v}N87Aq_SZC?yxgv@<+GKgyNgBGC)5?-M%E?;f z)HjIA$C~VGcu8Ja;jp L#srNh3IG5*N1~F3 literal 0 HcmV?d00001 diff --git a/icon_ada_stax.gif b/icon_ada_stax.gif new file mode 100644 index 0000000000000000000000000000000000000000..1bd3d3d49a55a12134570061457ceb3fbbf02605 GIT binary patch literal 130 zcmZ?wbhEHbRA5kGXkY+=|Ns9h{u6XAN=+*^z^Sh z{g!|6oGno->+bDI{mklcqgRG=;bhHKQ!I~dTv2OuIxcHp)8~(iU2_hK`L!2)jdByX fRFRxla5B+V({f(SjlS=%8M}`^*<=~Wz+epk({eO8 literal 0 HcmV?d00001 From a0de0ec83a28c4bf5579eff9b97c8ec538984f6f Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Thu, 22 Sep 2022 10:31:44 +0200 Subject: [PATCH 008/105] Fatstacks: adapt for new ui lib --- src/io.c | 10 +++++++--- src/io.h | 2 ++ src/main.c | 19 ++++++++++++++++--- src/uiElements.h | 2 ++ src/uiHelpers.c | 5 ++++- src/uiHelpers.h | 5 +++++ 6 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/io.c b/src/io.c index bddc5e26..e3cd3775 100644 --- a/src/io.c +++ b/src/io.c @@ -70,10 +70,12 @@ void io_send_buf(uint16_t code, uint8_t* buffer, size_t bufferSize) // Everything below this point is Ledger magic. // override point, but nothing more to do +#ifdef HAVE_BAGL void io_seproxyhal_display(const bagl_element_t* element) { - io_seproxyhal_display_default((bagl_element_t*)element); + io_seproxyhal_display_default(element); } +#endif unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B] = {0}; @@ -83,13 +85,13 @@ unsigned char io_event(unsigned char channel MARK_UNUSED) // can't have more than one tag in the reply, not supported yet. switch (G_io_seproxyhal_spi_buffer[0]) { case SEPROXYHAL_TAG_FINGER_EVENT: - // This app is not supposed to work with Blue - ASSERT(false); UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); break; case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: +#ifdef HAVE_BAGL UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); +#endif break; case SEPROXYHAL_TAG_STATUS_EVENT: @@ -102,7 +104,9 @@ unsigned char io_event(unsigned char channel MARK_UNUSED) break; case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: +#ifdef HAVE_BAGL UX_DISPLAYED_EVENT({}); +#endif break; case SEPROXYHAL_TAG_TICKER_EVENT: diff --git a/src/io.h b/src/io.h index c3253104..fa9aecb4 100644 --- a/src/io.h +++ b/src/io.h @@ -43,7 +43,9 @@ typedef enum { extern io_state_t io_state; // Everything below this point is Ledger magic +#ifdef HAVE_BAGL void io_seproxyhal_display(const bagl_element_t* element); +#endif #ifndef FUZZING unsigned char io_event(unsigned char channel); diff --git a/src/main.c b/src/main.c index 2188fec3..145609dc 100644 --- a/src/main.c +++ b/src/main.c @@ -41,6 +41,7 @@ STATIC_ASSERT(CX_APILEVEL >= 9, "bad api level"); static const int INS_NONE = -1; +#ifdef HAVE_BAGL // ui_idle displays the main menu. Note that your app isn't required to use a // menu as its idle screen; you can define your own completely custom screen. void ui_idle(void) @@ -63,6 +64,7 @@ void ui_idle(void) STATIC_ASSERT(false); #endif } +#endif static const uint8_t CLA = 0xD7; @@ -174,7 +176,12 @@ static void cardano_main(void) if (e >= _ERR_AUTORESPOND_START && e < _ERR_AUTORESPOND_END) { io_send_buf(e, NULL, 0); flags = IO_ASYNCH_REPLY; - ui_idle(); +#ifdef HAVE_NBGL + if (e != ERR_REJECTED_BY_USER) { + ui_idle(); + display_error(); + } +#endif } else { PRINTF("Uncaught error 0x%x", (unsigned) e); #ifdef RESET_ON_CRASH @@ -216,13 +223,15 @@ __attribute__((section(".boot"))) int main(void) __asm volatile("cpsie i"); for (;;) { +#ifdef HAVE_BAGL UX_INIT(); +#endif // HAVE_BAGL os_boot(); BEGIN_TRY { TRY { io_seproxyhal_init(); - #if defined(TARGET_NANOX) + #if defined(HAVE_BLE) // grab the current plane mode setting G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0); #endif @@ -231,9 +240,13 @@ __attribute__((section(".boot"))) int main(void) USB_power(1); ui_idle(); + #ifdef HAVE_NBGL + ui_idle_flow(); + #endif // HAVE_NBGL + #if defined(HAVE_BLE) BLE_power(0, NULL); - BLE_power(1, "Nano X ADA"); + BLE_power(1, NULL); #endif io_state = IO_EXPECT_IO; diff --git a/src/uiElements.h b/src/uiElements.h index 945ea061..0d8c697f 100644 --- a/src/uiElements.h +++ b/src/uiElements.h @@ -1,6 +1,7 @@ #ifndef H_CARDANO_APP_UI_ELEMENTS #define H_CARDANO_APP_UI_ELEMENTS +#ifdef HAVE_BAGL #include // These are helper macros for defining UI elements. There are four basic UI @@ -19,4 +20,5 @@ #define UI_ICON_RIGHT(userid, glyph) {{BAGL_ICON,userid,117,13,8,6,0,0,0,0xFFFFFF,0,0,glyph},NULL} #define UI_TEXT(userid, x, y, w, text) {{BAGL_LABELINE,userid,x,y,w,12,0,0,0,0xFFFFFF,0,BAGL_FONT_OPEN_SANS_REGULAR_11px|BAGL_FONT_ALIGNMENT_CENTER,0},(char *)text} +#endif // HAVE_BAGL #endif // H_CARDANO_APP_UI_ELEMENTS diff --git a/src/uiHelpers.c b/src/uiHelpers.c index fb7e82cb..60bccbcf 100644 --- a/src/uiHelpers.c +++ b/src/uiHelpers.c @@ -6,6 +6,7 @@ #include "io.h" #include "utils.h" #include "securityPolicy.h" +#include "ui.h" displayState_t displayState; @@ -18,13 +19,14 @@ displayState_t displayState; // ux is a magic global variable implicitly referenced by the UX_ macros. Apps // should never need to reference it directly ux_state_t ux; -#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) +#elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) || defined(TARGET_STAX) ux_state_t G_ux; bolos_ux_params_t G_ux_params; #endif STATIC_ASSERT(SIZEOF(uint8_t) == SIZEOF(char), "bad char size"); +#ifdef HAVE_BAGL void assert_uiPaginatedText_magic() { ASSERT(paginatedTextState->initMagic == INIT_MAGIC_PAGINATED_TEXT); @@ -216,6 +218,7 @@ void ui_displayPaginatedText( } #endif // HEADLESS } +#endif void respond_with_user_reject() { diff --git a/src/uiHelpers.h b/src/uiHelpers.h index f08e67e9..5c58f5aa 100644 --- a/src/uiHelpers.h +++ b/src/uiHelpers.h @@ -10,6 +10,11 @@ typedef void ui_callback_fn_t(); +#if defined(TARGET_NANOX) || defined(TARGET_NANOS2) || defined(TARGET_STAX) +extern ux_state_t G_ux; +extern bolos_ux_params_t G_ux_params; +#endif + // *INDENT-OFF* // Warning: Following macros are *NOT* brace-balanced by design! From 5b563bd9325ccc0c87a2356760dcd634e3929501 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 25 Oct 2022 11:00:05 +0200 Subject: [PATCH 009/105] nbgl: add ui for stax --- src/ui.h | 31 ++ src/uiScreens_nbgl.c | 775 +++++++++++++++++++++++++++++++++++++++++++ src/uiScreens_nbgl.h | 210 ++++++++++++ src/ui_menu_nbgl.c | 98 ++++++ src/ui_nbgl.c | 522 +++++++++++++++++++++++++++++ 5 files changed, 1636 insertions(+) create mode 100644 src/ui.h create mode 100644 src/uiScreens_nbgl.c create mode 100644 src/uiScreens_nbgl.h create mode 100644 src/ui_menu_nbgl.c create mode 100644 src/ui_nbgl.c diff --git a/src/ui.h b/src/ui.h new file mode 100644 index 00000000..85a7a578 --- /dev/null +++ b/src/ui.h @@ -0,0 +1,31 @@ +#ifndef H_CARDANO_APP_UI_H +#define H_CARDANO_APP_UI_H + +#include "io.h" +#include "uiHelpers.h" + +#ifdef HAVE_NBGL +typedef void (*callback_t)(void); + +void set_light_confirmation(bool needed); +void display_address(callback_t user_accept_cb, callback_t user_reject_cb); +void fill_address_data(char* text, char *content); +void fill_and_display_if_required(const char* line1, const char* line2, callback_t user_accept_cb, callback_t user_reject_cb); +void fill_and_display_new_page(const char* line1, const char* line2, callback_t user_accept_cb, callback_t user_reject_cb); +void force_display(callback_t user_accept_cb, callback_t user_reject_cb); +void display_confirmation(const char* text1, const char* text2, const char* confirmText, const char* rejectText, callback_t user_accept_cb, callback_t user_reject_cb); +void display_page(callback_t user_accept_cb, callback_t user_reject_cb); +void display_prompt(const char* text1, const char* text2, callback_t user_accept_cb, callback_t user_reject_cb); +void display_warning(const char* text, callback_t user_accept_cb, callback_t user_reject_cb); +void ui_idle(void); +void ui_idle_flow(void); +void display_cancel_message(void); +void display_error(void); +void nbgl_reset_transaction_full_context(void); +#endif + +#ifdef HAVE_BAGL +void io_seproxyhal_display(const bagl_element_t *element); +#endif // HAVE_BAGL + +#endif // H_CARDANO_APP_UI_H diff --git a/src/uiScreens_nbgl.c b/src/uiScreens_nbgl.c new file mode 100644 index 00000000..d781abd7 --- /dev/null +++ b/src/uiScreens_nbgl.c @@ -0,0 +1,775 @@ +#ifdef HAVE_NBGL +#include "uiScreens_nbgl.h" +#include "bech32.h" +#include "cardano.h" +#include "hexUtils.h" +#include "ipUtils.h" +#include "textUtils.h" +#include "signTx.h" +#include "signTxPoolRegistration.h" +#include "tokens.h" + +// encodes a buffer into bech32 and displays it (works for bufferSize <= 150 and prefix length <= 12) +void ui_getBech32Screen( + char* line, + const size_t lineSize, + const char* bech32Prefix, + const uint8_t* buffer, size_t bufferSize +) +{ + { + // assert inputs + ASSERT(strlen(bech32Prefix) > 0); + ASSERT(strlen(bech32Prefix) <= BECH32_PREFIX_LENGTH_MAX); + + ASSERT(bufferSize <= BECH32_BUFFER_SIZE_MAX); + } + + // rough upper bound on required size is used + explicit_bzero(line, lineSize); + + { + size_t len = bech32_encode(bech32Prefix, buffer, bufferSize, line, lineSize); + + ASSERT(len == strlen(line)); + ASSERT(len + 1 < lineSize); + } +} + +void ui_getHexBufferScreen( + char* line, + const size_t lineSize, + const uint8_t* buffer, size_t bufferSize +) +{ + ASSERT(bufferSize > 0); + ASSERT(bufferSize <= 32); // this is used for hashes, all are <= 32 bytes + + explicit_bzero(line, lineSize); + + size_t length = encode_hex( + buffer, bufferSize, + line, lineSize + ); + ASSERT(length == strlen(line)); + ASSERT(length == 2 * bufferSize); +} + +void ui_getPathScreen( + char* line, + const size_t lineSize, + const bip44_path_t* path +) +{ + explicit_bzero(line, lineSize); + bip44_printToStr(path, line, lineSize); + ASSERT(strlen(line) + 1 < lineSize); +} + +__noinline_due_to_stack__ +static void _ui_getAccountWithDescriptionScreen( + char* accountDescription, + const size_t accountDescriptionSize, + const bip44_path_t* path +) +{ + explicit_bzero(accountDescription, accountDescriptionSize); + + ASSERT(bip44_hasOrdinaryWalletKeyPrefix(path)); + ASSERT(bip44_containsAccount(path)); + { + bip44_printToStr(path, accountDescription, accountDescriptionSize); + } + + { + size_t len = strlen(accountDescription); + ASSERT(len > 0); + ASSERT(len + 1 < accountDescriptionSize); + } +} + + +void ui_getPublicKeyType( + char* line, + const size_t lineSize, + const bip44_path_t* path +) +{ + switch (bip44_classifyPath(path)) { + case PATH_POOL_COLD_KEY: { + strncpy(line, "Export\nCold public key", lineSize); + return; + } + + case PATH_ORDINARY_ACCOUNT: + // Fallthrough + default: + strncpy(line, "Export\nPublic key", lineSize); + return; + } +} + +// the given path typically corresponds to an account +// if it contains anything more, we display just the whole path +void ui_getPublicKeyPathScreen( + char* line1, + const size_t line1Size, + char* line2, + const size_t line2Size, + const bip44_path_t* path +) +{ + switch (bip44_classifyPath(path)) { + case PATH_POOL_COLD_KEY: { + strncpy(line1, "Cold public key", line1Size); + + ui_getPathScreen( + line2, + line2Size, + path + ); + return; + } + + case PATH_ORDINARY_ACCOUNT: { + strncpy(line1, "Public key", line1Size); + _ui_getAccountWithDescriptionScreen(line2, line2Size, path); + return; + } + + default: + strncpy(line1, "Public key", line1Size); + ui_getPathScreen( + line2, + line2Size, + path + ); + return; + } +} + +void ui_getStakingKeyScreen( + char* line, + const size_t lineSize, + const bip44_path_t* stakingPath +) +{ + ASSERT(bip44_isOrdinaryStakingKeyPath(stakingPath)); + + explicit_bzero(line, lineSize); + + _ui_getAccountWithDescriptionScreen( + line, + lineSize, + stakingPath + ); +} + +void ui_getAccountScreeen( + char* line1, + const size_t line1Size, + char* line2, + const size_t line2Size, + const bip44_path_t* path +) +{ + explicit_bzero(line1, line1Size); + explicit_bzero(line2, line2Size); + + uint32_t account = unharden(bip44_getAccount(path)); + STATIC_ASSERT(sizeof(account + 1) <= sizeof(unsigned), "oversized type for %u"); + STATIC_ASSERT(!IS_SIGNED(account + 1), "signed type for %u"); + if (bip44_hasByronPrefix(path)) { + snprintf( + line1, line1Size, + "Byron account" + ); + snprintf( + line2, line2Size, + "#%u", + account + 1 + ); + } else if (bip44_hasShelleyPrefix(path)) { + snprintf( + line1, line1Size, + "Account" + ); + snprintf( + line2, line2Size, + "#%u", + account + 1 + ); + } else { + ASSERT(false); + } +} + +// bech32 for Shelley, base58 for Byron +void ui_getAddressScreen( + char* line, + const size_t lineSize, + const uint8_t* addressBuffer, size_t addressSize +) +{ + ASSERT(addressSize > 0); + ASSERT(addressSize < BUFFER_SIZE_PARANOIA); + + explicit_bzero(line, lineSize); + + size_t length = humanReadableAddress( + addressBuffer, addressSize, + line, lineSize + ); + ASSERT(length > 0); + ASSERT(strlen(line) == length); +} + +// display bech32-encoded reward account preceded by staking key derivation path (if given) +static void _getRewardAccountWithDescriptionScreen( + char* line, + const size_t lineSize, + const key_reference_type_t keyReferenceType, + const bip44_path_t* path, + const uint8_t* rewardAccountBuffer +) +{ + explicit_bzero(line, lineSize); + size_t descLen = 0; // line length + + if (keyReferenceType == KEY_REFERENCE_PATH) { + descLen += bip44_printToStr(path, line, lineSize); + } + { + // add bech32-encoded reward account + ASSERT(descLen < BIP44_PATH_STRING_SIZE_MAX); + ASSERT(descLen + 1 < lineSize); + + if (descLen > 0) { + // add a space after path if the path is present + ASSERT(descLen + 2 < lineSize); + line[descLen++] = ' '; + line[descLen] = '\0'; + } + + { + descLen += humanReadableAddress( + rewardAccountBuffer, REWARD_ACCOUNT_SIZE, + line + descLen, lineSize - descLen + ); + } + ASSERT(descLen == strlen(line)); + ASSERT(descLen + 1 < lineSize); + } +} + +// displays bech32-encoded reward account preceded by path (if given) +void ui_getRewardAccountScreen( + char *firstLine, + const size_t firstLineSize, + char *secondLine, + const size_t secondLineSize, + const reward_account_t* rewardAccount, + uint8_t networkId +) +{ + // WARNING: reward account must be displayed in full (not just a key derivation path) + // because the network id security policy relies on it + + ASSERT(isValidNetworkId(networkId)); + + uint8_t rewardAccountBuffer[REWARD_ACCOUNT_SIZE] = {0}; + explicit_bzero(firstLine, firstLineSize); + + switch (rewardAccount->keyReferenceType) { + + case KEY_REFERENCE_PATH: { + ASSERT(bip44_isOrdinaryStakingKeyPath(&rewardAccount->path)); + + { + uint32_t account = unharden(bip44_getAccount(&rewardAccount->path)); + STATIC_ASSERT(sizeof(account + 1) <= sizeof(unsigned), "oversized type for %u"); + STATIC_ASSERT(!IS_SIGNED(account + 1), "signed type for %u"); + snprintf( + firstLine, firstLineSize, + "Reward account #%u ", account + 1 + ); + } + + constructRewardAddressFromKeyPath( + &rewardAccount->path, networkId, + rewardAccountBuffer, SIZEOF(rewardAccountBuffer) + ); + break; + } + + case KEY_REFERENCE_HASH: { + snprintf( + firstLine, firstLineSize, + "Reward account" + ); + + STATIC_ASSERT(SIZEOF(rewardAccountBuffer) == REWARD_ACCOUNT_SIZE, "wrong reward account buffer size"); + STATIC_ASSERT(SIZEOF(rewardAccount->hashBuffer) == REWARD_ACCOUNT_SIZE, "wrong reward account hash buffer size"); + memmove(rewardAccountBuffer, rewardAccount->hashBuffer, REWARD_ACCOUNT_SIZE); + break; + } + + default: + ASSERT(false); + } + + { + const size_t len = strlen(firstLine); + ASSERT(len > 0); + // make sure all the information is displayed to the user + ASSERT(len + 1 < firstLineSize); + } + + _getRewardAccountWithDescriptionScreen( + secondLine, + secondLineSize, + rewardAccount->keyReferenceType, + &rewardAccount->path, + rewardAccountBuffer + ); +} + +void ui_getSpendingInfoScreen( + char *line1, + const size_t line1Size, + char *line2, + const size_t line2Size, + const addressParams_t* addressParams +) +{ + switch (determineSpendingChoice(addressParams->type)) { + + case SPENDING_PATH: { + snprintf(line1, line1Size, "Spending path"); + ui_getPathScreen( + line2, + line2Size, + &addressParams->spendingKeyPath + ); + return; + } + + case SPENDING_SCRIPT_HASH: { + snprintf(line1, line1Size, "Spending script hash"); + ui_getBech32Screen( + line2, + line2Size, + "script", + addressParams->spendingScriptHash, + SIZEOF(addressParams->spendingScriptHash) + ); + return; + } + + default: { + // includes SPENDING_NONE + ASSERT(false); + } + } +} + +static const char STAKING_HEADING_PATH[] = "Staking key path"; +static const char STAKING_HEADING_KEY_HASH[] = "Staking key hash"; +static const char STAKING_HEADING_SCRIPT_HASH[] = "Staking script hash"; +static const char STAKING_HEADING_POINTER[] = "Staking key pointer"; +static const char STAKING_HEADING_WARNING[] = "WARNING:"; + +void ui_getStakingInfoScreen( + char* line1, + const size_t line1Size, + char* line2, + const size_t line2Size, + const addressParams_t* addressParams +) +{ + explicit_bzero(line2, line2Size); + + switch (addressParams->stakingDataSource) { + + case NO_STAKING: { + switch (addressParams->type) { + + case BYRON: + strncpy(line1, STAKING_HEADING_WARNING, line1Size); + strncpy(line2, "Legacy Byron address\n(no staking rewards)", line2Size); + break; + + case ENTERPRISE_KEY: + case ENTERPRISE_SCRIPT: + strncpy(line1, STAKING_HEADING_WARNING, line1Size); + strncpy(line2, "No staking rewards", line2Size); + break; + + default: + ASSERT(false); + } + break; + } + + case STAKING_KEY_PATH: { + strncpy(line1, STAKING_HEADING_PATH, line1Size); + bip44_printToStr(&addressParams->stakingKeyPath, line2, line2Size); + break; + } + + case STAKING_KEY_HASH: { + strncpy(line1, STAKING_HEADING_KEY_HASH, line1Size); + bech32_encode( + "stake_vkh", // shared keys never go into address directly + addressParams->stakingKeyHash, SIZEOF(addressParams->stakingKeyHash), + line2, line2Size + ); + break; + } + + case STAKING_SCRIPT_HASH: { + strncpy(line1, STAKING_HEADING_SCRIPT_HASH, line1Size); + bech32_encode( + "script", + addressParams->stakingScriptHash, SIZEOF(addressParams->stakingScriptHash), + line2, line2Size + ); + break; + } + + case BLOCKCHAIN_POINTER: + strncpy(line1, STAKING_HEADING_POINTER, line1Size); + printBlockchainPointerToStr(addressParams->stakingKeyBlockchainPointer, line2, line2Size); + break; + + + default: + ASSERT(false); + } + + ASSERT(line1 != NULL); + ASSERT(strlen(line2) > 0); + ASSERT(strlen(line2) + 1 < line2Size); +} + +void ui_getAssetFingerprintScreen( + char* line, + const size_t lineSize, + const token_group_t* tokenGroup, + const uint8_t* assetNameBytes, size_t assetNameSize +) +{ + ASSERT(assetNameSize <= ASSET_NAME_SIZE_MAX); + + explicit_bzero(line, lineSize); + + deriveAssetFingerprintBech32( + tokenGroup->policyId, SIZEOF(tokenGroup->policyId), + assetNameBytes, assetNameSize, + line, lineSize + ); + ASSERT(strlen(line) + 1 < lineSize); +} + +void ui_getAdaAmountScreen( + char* line, + const size_t lineSize, + uint64_t amount +) +{ + explicit_bzero(line, lineSize); + str_formatAdaAmount(amount, line, lineSize); +} + +void ui_getTokenAmountOutputScreen( + char* line, + const size_t lineSize, + const token_group_t* tokenGroup, + const uint8_t* assetNameBytes, size_t assetNameSize, + uint64_t tokenAmount +) +{ + explicit_bzero(line, lineSize); + str_formatTokenAmountOutput( + tokenGroup, + assetNameBytes, assetNameSize, + tokenAmount, + line, lineSize + ); +} + +void ui_getTokenAmountMintScreen( + char* line, + const size_t lineSize, + const token_group_t* tokenGroup, + const uint8_t* assetNameBytes, size_t assetNameSize, + int64_t tokenAmount +) +{ + explicit_bzero(line, lineSize); + str_formatTokenAmountMint( + tokenGroup, + assetNameBytes, assetNameSize, + tokenAmount, + line, lineSize + ); +} + +void ui_getUint64Screen( + char* line, + const size_t lineSize, + uint64_t value +) +{ + explicit_bzero(line, lineSize); + str_formatUint64(value, line, lineSize); +} + +void ui_getInt64Screen( + char* line, + const size_t lineSize, + uint64_t value +) +{ + explicit_bzero(line, lineSize); + str_formatInt64(value, line, lineSize); +} + +void ui_getValidityBoundaryScreen( + char* line, + const size_t lineSize, + uint64_t boundary, + uint8_t networkId, uint32_t protocolMagic +) +{ + if ((networkId == MAINNET_NETWORK_ID) && (protocolMagic == MAINNET_PROTOCOL_MAGIC)) { + // nicer formatting could only be used for mainnet + // since it depends on network params that could differ for testnets + str_formatValidityBoundary(boundary, line, lineSize); + } else { + ui_getUint64Screen( + line, + lineSize, + boundary + ); + } +} + +void ui_getNetworkParamsScreen_1( + char* line, + const size_t lineSize, + uint8_t networkId +) +{ + ASSERT(isValidNetworkId(networkId)); + + explicit_bzero(line, lineSize); + + STATIC_ASSERT(sizeof(networkId) <= sizeof(unsigned), "oversized type for %u"); + STATIC_ASSERT(!IS_SIGNED(networkId), "signed type for %u"); + snprintf( + line, lineSize, + "%u", + networkId + ); + ASSERT(strlen(line) + 1 < lineSize); +} + +void ui_getNetworkParamsScreen_2( + char* line, + const size_t lineSize, + uint32_t protocolMagic +) +{ + explicit_bzero(line, lineSize); + + STATIC_ASSERT(sizeof(protocolMagic) <= sizeof(unsigned), "oversized type for %u"); + STATIC_ASSERT(!IS_SIGNED(protocolMagic), "signed type for %u"); + snprintf( + line, lineSize, + "%u", + protocolMagic + ); + ASSERT(strlen(line) + 1 < lineSize); +} + +void ui_getPoolMarginScreen( + char* line1, size_t lineSize, + uint64_t marginNumerator, uint64_t marginDenominator +) +{ + ASSERT(marginDenominator != 0); + ASSERT(marginNumerator <= marginDenominator); + ASSERT(marginDenominator <= MARGIN_DENOMINATOR_MAX); + + explicit_bzero(line1, lineSize); + + { + // marginPercentage is a multiple of 1/100th of 1%, i.e. the fractional part of the percentage has two digits + // adding marginDenominator / 2 to have a rounded result + uint64_t marginPercentage = (10000 * marginNumerator + (marginDenominator / 2)) / marginDenominator; + ASSERT(marginPercentage <= 10000); + + const unsigned int percentage = (unsigned int) marginPercentage; + + STATIC_ASSERT(sizeof(percentage) <= sizeof(unsigned), "oversized type for %u"); + STATIC_ASSERT(!IS_SIGNED(percentage), "signed type for %u"); + snprintf(line1, lineSize, "%u.%u %%", percentage / 100, percentage % 100); + ASSERT(strlen(line1) + 1 < lineSize); + } + + TRACE("%s", line1); +} + +void ui_getPoolOwnerScreen( + char* firstLine, + const size_t firstLineSize, + char* secondLine, + const size_t secondLineSize, + const pool_owner_t* owner, + uint32_t ownerIndex, + uint8_t networkId +) +{ + { + ASSERT(isValidNetworkId(networkId)); + ASSERT(ownerIndex < POOL_MAX_OWNERS); + } + { + uint8_t rewardAddress[REWARD_ACCOUNT_SIZE] = {0}; + + switch (owner->keyReferenceType) { + case KEY_REFERENCE_PATH: { + ASSERT(bip44_isOrdinaryStakingKeyPath(&owner->path)); + + constructRewardAddressFromKeyPath( + &owner->path, networkId, rewardAddress, SIZEOF(rewardAddress) + ); + break; + } + case KEY_REFERENCE_HASH: { + STATIC_ASSERT(SIZEOF(owner->keyHash) == ADDRESS_KEY_HASH_LENGTH, "wrong owner.keyHash size"); + + constructRewardAddressFromHash( + networkId, REWARD_HASH_SOURCE_KEY, + owner->keyHash, SIZEOF(owner->keyHash), + rewardAddress, SIZEOF(rewardAddress) + ); + break; + } + default: + ASSERT(false); + } + + explicit_bzero(firstLine, firstLineSize); + STATIC_ASSERT(sizeof(ownerIndex + 1) <= sizeof(unsigned), "oversized type for %u"); + STATIC_ASSERT(!IS_SIGNED(ownerIndex + 1), "signed type for %u"); + // indexed from 0 as discuss with IOHK on Slack + snprintf(firstLine, firstLineSize, "Owner #%u", ownerIndex); + // make sure all the information is displayed to the user + ASSERT(strlen(firstLine) + 1 < firstLineSize); + + _getRewardAccountWithDescriptionScreen( + secondLine, + secondLineSize, + owner->keyReferenceType, + &owner->path, + rewardAddress + ); + } +} + +// displays pool relay index +void ui_getPoolRelayScreen( + char* line, const size_t lineSize, + size_t relayIndex +) +{ + explicit_bzero(line, lineSize); + { + STATIC_ASSERT(sizeof(relayIndex + 1) <= sizeof(unsigned), "oversized type for %u"); + STATIC_ASSERT(!IS_SIGNED(relayIndex + 1), "signed type for %u"); + // indexed from 0 as discussed with IOHK on Slack + snprintf(line, lineSize, "#%u", relayIndex); + // make sure all the information is displayed to the user + ASSERT(strlen(line) + 1 < lineSize); + } +} + +void ui_getIpv4Screen( + char* ipStr, const size_t ipStrSize, + const ipv4_t* ipv4 +) +{ + explicit_bzero(ipStr, ipStrSize); + + if (ipv4->isNull) { + snprintf(ipStr, ipStrSize, "(none)"); + } else { + inet_ntop4(ipv4->ip, ipStr, ipStrSize); + } + + // make sure all the information is displayed to the user + ASSERT(strlen(ipStr) + 1 < ipStrSize); +} + +void ui_getIpv6Screen( + char* ipStr, const size_t ipStrSize, + const ipv6_t* ipv6 +) +{ + explicit_bzero(ipStr, ipStrSize); + + if (ipv6->isNull) { + snprintf(ipStr, ipStrSize, "(none)"); + } else { + inet_ntop6(ipv6->ip, ipStr, ipStrSize); + } + + // make sure all the information is displayed to the user + ASSERT(strlen(ipStr) + 1 < ipStrSize); +} + +void ui_getIpPortScreen( + char* portStr, const size_t portStrSize, + const ipport_t* port +) +{ + explicit_bzero(portStr, portStrSize); + + if (port->isNull) { + snprintf(portStr, portStrSize, "(none)"); + } else { + STATIC_ASSERT(sizeof(port->number) <= sizeof(unsigned), "oversized variable for %u"); + STATIC_ASSERT(!IS_SIGNED(port->number), "signed type for %u"); + snprintf(portStr, portStrSize, "%u", port->number); + } + + // make sure all the information is displayed to the user + ASSERT(strlen(portStr) + 1 < portStrSize); +} + +void ui_getInputScreen( + char* line, + const size_t lineSize, + const sign_tx_transaction_input_t* input) +{ + const tx_input_t* inputData = &input->input_data; + ASSERT(SIZEOF(inputData->txHashBuffer) == TX_HASH_LENGTH); + char txHex[2 * TX_HASH_LENGTH + 1] = {0}; + explicit_bzero(txHex, SIZEOF(txHex)); + + size_t length = encode_hex( + inputData->txHashBuffer, TX_HASH_LENGTH, + txHex, SIZEOF(txHex) + ); + ASSERT(length == strlen(txHex)); + ASSERT(length == 2 * TX_HASH_LENGTH); + + explicit_bzero(line, lineSize); + + snprintf(line, lineSize, "%u / %s", inputData->index, txHex); + // make sure all the information is displayed to the user + ASSERT(strlen(line) + 1 < lineSize); +} +#endif // HAVE_NBGL diff --git a/src/uiScreens_nbgl.h b/src/uiScreens_nbgl.h new file mode 100644 index 00000000..ea79a59e --- /dev/null +++ b/src/uiScreens_nbgl.h @@ -0,0 +1,210 @@ +#ifndef H_CARDANO_APP_UI_SCREENS_NBGL +#define H_CARDANO_APP_UI_SCREENS_NBGL + +#include "uiHelpers.h" +#include "addressUtilsShelley.h" +#include "signTx.h" +#include "signTxOutput.h" +#include "signTxPoolRegistration.h" +#include "bech32.h" +#include "ui.h" + +__noinline_due_to_stack__ +void ui_getBech32Screen( + char* line, + const size_t lineSize, + const char* bech32Prefix, + const uint8_t* buffer, size_t bufferSize +); + +__noinline_due_to_stack__ +void ui_getHexBufferScreen( + char* line, + const size_t lineSize, + const uint8_t* buffer, size_t bufferSize +); + +__noinline_due_to_stack__ +void ui_getPathScreen( + char* line, + const size_t lineSize, + const bip44_path_t* path +); + +__noinline_due_to_stack__ +void ui_getPublicKeyPathScreen( + char* line1, + const size_t line1Size, + char* line2, + const size_t line2Size, + const bip44_path_t* path +); + +__noinline_due_to_stack__ +void ui_getStakingKeyScreen( + char* line, + const size_t lineSize, + const bip44_path_t* stakingPath +); + +__noinline_due_to_stack__ +void ui_getAddressScreen( + char* line, + const size_t lineSize, + const uint8_t* addressBuffer, size_t addressSize +); + +__noinline_due_to_stack__ +void ui_getAccountScreeen( + char* line1, + const size_t line1Size, + char* line2, + const size_t line2Size, + const bip44_path_t* path +); + +__noinline_due_to_stack__ +void ui_getRewardAccountScreen( + char *firstLine, + const size_t firstLineSize, + char *secondLine, + const size_t secondLineSize, + const reward_account_t* rewardAccount, + uint8_t networkId +); + +__noinline_due_to_stack__ +void ui_getSpendingInfoScreen( + char *line1, + const size_t line1Size, + char *line2, + const size_t line2Size, + const addressParams_t* addressParams +); + +__noinline_due_to_stack__ +void ui_getStakingInfoScreen( + char* line1, + const size_t line1Size, + char* line2, + const size_t line2Size, + const addressParams_t* addressParams +); + +__noinline_due_to_stack__ +void ui_getAssetFingerprintScreen( + char* line, + const size_t lineSize, + const token_group_t* tokenGroup, + const uint8_t* assetNameBytes, size_t assetNameSize +); + +__noinline_due_to_stack__ +void ui_getAdaAmountScreen( + char* line, + const size_t lineSize, + uint64_t amount +); + +__noinline_due_to_stack__ +void ui_getTokenAmountOutputScreen( + char* line, + const size_t lineSize, + const token_group_t* tokenGroup, + const uint8_t* assetNameBytes, size_t assetNameSize, + uint64_t tokenAmount +); + +__noinline_due_to_stack__ +void ui_getTokenAmountMintScreen( + char* line, + const size_t lineSize, + const token_group_t* tokenGroup, + const uint8_t* assetNameBytes, size_t assetNameSize, + int64_t tokenAmount +); +__noinline_due_to_stack__ +void ui_getUint64Screen( + char* line, + const size_t lineSize, + uint64_t value +); + +__noinline_due_to_stack__ +void ui_getInt64Screen( + char* line, + const size_t lineSize, + uint64_t value +); + +__noinline_due_to_stack__ +void ui_getValidityBoundaryScreen( + char* line, + const size_t lineSize, + uint64_t boundary, + uint8_t networkId, uint32_t protocolMagic +); + +__noinline_due_to_stack__ +void ui_getNetworkParamsScreen_1( + char* line, + const size_t lineSize, + uint8_t networkId +); + +__noinline_due_to_stack__ +void ui_getNetworkParamsScreen_2( + char* line, + const size_t lineSize, + uint32_t protocolMagic +); + +__noinline_due_to_stack__ +void ui_getPoolMarginScreen( + char* line1, const size_t lineSize, + uint64_t marginNumerator, uint64_t marginDenominator +); + +__noinline_due_to_stack__ +void ui_getPoolOwnerScreen( + char* firstLine, + const size_t firstLineSize, + char* secondLine, + const size_t secondLineSize, + const pool_owner_t* owner, + uint32_t ownerIndex, + uint8_t networkId +); + +__noinline_due_to_stack__ +void ui_getPoolRelayScreen( + char* line, const size_t lineSize, + size_t relayIndex +); + +__noinline_due_to_stack__ +void ui_getIpv4Screen( + char* ipStr, const size_t ipStrSize, + const ipv4_t* ipv4 +); + +__noinline_due_to_stack__ +void ui_getIpv6Screen( + char* ipStr, const size_t ipStrSize, + const ipv6_t* ipv6 +); + +__noinline_due_to_stack__ +void ui_getIpPortScreen( + char* portStr, const size_t portStrSize, + const ipport_t* port +); + +__noinline_due_to_stack__ +void ui_getInputScreen( + char* line, + const size_t lineSize, + const sign_tx_transaction_input_t* input +); + +#endif // H_CARDANO_APP_UI_SCREENS_NBGL diff --git a/src/ui_menu_nbgl.c b/src/ui_menu_nbgl.c new file mode 100644 index 00000000..ae75c9b3 --- /dev/null +++ b/src/ui_menu_nbgl.c @@ -0,0 +1,98 @@ +/******************************************************************************* + ** Ledger App - Cardano Wallet (c) 2022 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ +#ifdef HAVE_NBGL +#include "app_mode.h" +#include "nbgl_page.h" +#include "nbgl_touch.h" +#include "nbgl_use_case.h" +#include "state.h" +#include "ui.h" +#include "uiHelpers.h" +#include "uiScreens_nbgl.h" + +#define PAGE_START 0 +#define NB_PAGE_SETTING 2 +#define IS_TOUCHABLE false +#define NB_INFO_FIELDS 3 +#define NB_SETTINGS_SWITCHES 1 + +enum { + SWITCH_APP_MODE_TOKEN = FIRST_USER_TOKEN, +}; + +static nbgl_layoutSwitch_t switches[NB_SETTINGS_SWITCHES]; + +static const char *const infoTypes[] = {"Version", "Developer", "Copyright"}; +static const char *const infoContents[] = {APPVERSION, "Vacuumlabs", + "(c) 2022 Ledger"}; +static const int INS_NONE = -1; + +// Settings +static void exit(void) { os_sched_exit(-1); } + +static bool settings_navigation_callback(uint8_t page, nbgl_pageContent_t *content) { + if (page == 0) { + switches[0].text = (char *)"Enable expert mode"; + switches[0].subText = (char *)"Select application mode"; + switches[0].token = SWITCH_APP_MODE_TOKEN; + switches[0].tuneId = TUNE_TAP_CASUAL; + switches[0].initState = app_mode_expert(); + + content->type = SWITCHES_LIST; + content->switchesList.nbSwitches = NB_SETTINGS_SWITCHES; + content->switchesList.switches = (nbgl_layoutSwitch_t *)switches; + } else if (page == 1) { + content->type = INFOS_LIST; + content->infosList.nbInfos = NB_INFO_FIELDS; + content->infosList.infoTypes = (const char **)infoTypes; + content->infosList.infoContents = (const char **)infoContents; + } else { + return false; + } + return true; +} + +static void settings_control_callback(int token, uint8_t index) { + UNUSED(index); + switch (token) { + case SWITCH_APP_MODE_TOKEN: + app_mode_set_expert(index); + break; + + default: + PRINTF("Should not happen !"); + break; + } +} + +static void ui_menu_settings(void) { + nbgl_useCaseSettings((char *)"Cardano settings", PAGE_START, NB_PAGE_SETTING, + IS_TOUCHABLE, ui_idle_flow, settings_navigation_callback, + settings_control_callback); +} + +void ui_idle_flow(void) { + TRACE("RESETTING\n\n"); + // We need to make sure the ui context is reset even if the app restarts + nbgl_reset_transaction_full_context(); + nbgl_useCaseHome((char *)"Cardano", &C_cardano_64, NULL, true, + ui_menu_settings, exit); +} + +void ui_idle(void) { + currentInstruction = INS_NONE; +} +#endif // HAVE_NBGL diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c new file mode 100644 index 00000000..777d8af9 --- /dev/null +++ b/src/ui_nbgl.c @@ -0,0 +1,522 @@ +/******************************************************************************* + ** Ledger App - Cardano Wallet (c) 2022 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ +#ifdef HAVE_NBGL +#include "app_mode.h" +#include "nbgl_use_case.h" +#include "state.h" +#include "ui.h" +#include "uiHelpers.h" +#include "uiScreens_nbgl.h" + +#define MAX_LINE_PER_PAGE_COUNT 10 +#define MAX_TAG_CONTENT_CHAR_PER_LINE 18 +#define MAX_TAG_PER_PAGE_COUNT 4 +#define MAX_TAG_TITLE_LINE_LENGTH 30 +#define MAX_TAG_CONTENT_LENGTH 200 +#define MAX_TEXT_STRING 50 +#define PENDING_ELEMENT_INDEX MAX_TAG_PER_PAGE_COUNT +enum { + CANCEL_PROMPT_TOKEN = 1, + ACCEPT_PAGE_TOKEN, + CONFIRMATION_STATUS_TOKEN, +}; + +typedef struct { + char *confirmedStatus; // text displayed in confirmation page (after long press) + char *rejectedStatus; // text displayed in rejection page (after reject confirmed) + callback_t approvedCallback; + callback_t rejectedCallback; + callback_t pendingDisplayPageFn; + bool pendingElement; + uint8_t currentLineCount; + uint8_t currentElementCount; + char tagTitle[MAX_TAG_PER_PAGE_COUNT + 1][MAX_TAG_TITLE_LINE_LENGTH]; + char tagContent[MAX_TAG_PER_PAGE_COUNT + 1][MAX_TAG_CONTENT_LENGTH]; + char pageText[2][MAX_TEXT_STRING]; + bool lightConfirmation; + nbgl_layoutTagValueList_t pairList; +} UiContext_t; + +static nbgl_page_t *pageContext; +static nbgl_layoutTagValue_t tagValues[5]; +static UiContext_t uiContext = { + .rejectedStatus = NULL, + .confirmedStatus = NULL, + .currentLineCount = 0, + .currentElementCount = 0, + .pendingElement = false, + .lightConfirmation = 0, +}; + +// Forward declaration +static void display_cancel(void); +static void display_confirmation_status(void); +static void display_cancel_status(void); +static void trigger_callback(callback_t userAcceptCallback); + +static void release_context(void) { + if (pageContext != NULL) { + nbgl_pageRelease(pageContext); + pageContext = NULL; + } +} + +static inline uint8_t get_element_line_count(const char *line) { + return strlen(line) / MAX_TAG_CONTENT_CHAR_PER_LINE + 2; +} + +static void set_callbacks(callback_t approvedCallback, callback_t rejectedCallback){ + uiContext.approvedCallback = approvedCallback; + uiContext.rejectedCallback = rejectedCallback; +} + +static void fill_current_element(const char* text, const char* content) { + strncpy(uiContext.tagTitle[uiContext.currentElementCount], text, MAX_TAG_TITLE_LINE_LENGTH); + strncpy(uiContext.tagContent[uiContext.currentElementCount], content, MAX_TAG_CONTENT_LENGTH); + + uiContext.currentElementCount++; + uiContext.currentLineCount += get_element_line_count(content); +} + +static void fill_pending_element(const char* text, const char* content) { + strncpy(uiContext.tagTitle[PENDING_ELEMENT_INDEX], text, MAX_TAG_TITLE_LINE_LENGTH); + strncpy(uiContext.tagContent[PENDING_ELEMENT_INDEX], content, MAX_TAG_CONTENT_LENGTH); + + uiContext.pendingElement = true; +} + +static void reset_transaction_current_context(void) { + uiContext.currentElementCount = 0; + uiContext.currentLineCount = 0; +} + +void nbgl_reset_transaction_full_context(void) { + reset_transaction_current_context(); + uiContext.pendingElement = 0; + uiContext.lightConfirmation = false; + uiContext.rejectedStatus = NULL; + uiContext.confirmedStatus = NULL; + uiContext.approvedCallback = NULL; + uiContext.rejectedCallback = NULL; + uiContext.pendingDisplayPageFn = NULL; +} + +void set_light_confirmation(bool needed) { + uiContext.lightConfirmation = needed; +} + +static void display_callback(int token, unsigned char index) { + (void)index; + callback_t callback; + + release_context(); + + switch (token) { + case CANCEL_PROMPT_TOKEN: + display_cancel(); + break; + case ACCEPT_PAGE_TOKEN: + if (uiContext.pendingDisplayPageFn) { + // Hook the approve callback so that the pending page is displayed + // Once this page is approved, the approve callback will be called + callback = uiContext.pendingDisplayPageFn; + uiContext.pendingDisplayPageFn = NULL; + } else { + callback = uiContext.approvedCallback; + } + callback(); + break; + case CONFIRMATION_STATUS_TOKEN: + display_confirmation_status(); + break; + default: + TRACE("%d unknown", token); + } +} + +static void _display_confirmation(void) { + TRACE("_confirmation"); + + release_context(); + + nbgl_pageNavigationInfo_t info = { + .activePage = 0, + .nbPages = 0, + .navType = NAV_WITH_TAP, + .progressIndicator = true, + .navWithTap.backButton = false, + .navWithTap.nextPageText = NULL, + .navWithTap.quitText = "Reject", + .quitToken = CANCEL_PROMPT_TOKEN, + .tuneId = TUNE_TAP_CASUAL}; + + nbgl_pageContent_t content = { + .type = INFO_LONG_PRESS, + .infoLongPress.icon = &C_cardano_64, + .infoLongPress.text = uiContext.pageText[0], + .infoLongPress.longPressText = (char *)"Hold to approve", + .infoLongPress.longPressToken = CONFIRMATION_STATUS_TOKEN, + .infoLongPress.tuneId = TUNE_TAP_NEXT}; + + pageContext = nbgl_pageDrawGenericContent(&display_callback, &info, &content); + +#ifdef HEADLESS + nbgl_refresh(); + trigger_callback(uiContext.approvedCallback); +#endif +} + +static void light_confirm_callback(bool confirm) { + if (confirm) { + display_confirmation_status(); + } else { + display_cancel_status(); + } +} + +static void _display_light_confirmation(void) { + TRACE("_light_confirmation"); + + nbgl_useCaseChoice(&C_cardano_64, uiContext.pageText[0], (char *)"", + (char *)"Confirm", (char *)"Cancel", light_confirm_callback); + +#ifdef HEADLESS + trigger_callback(uiContext.approvedCallback); +#endif +} + +static void display_cancel(void) { + if (uiContext.lightConfirmation) { + display_cancel_status(); + } else { + nbgl_useCaseConfirm((char *)"Reject ?", NULL, (char *)"Yes, Reject", + (char *)"Go back", display_cancel_status); + } +} + +static void cancellation_status_callback(void) { + if (uiContext.rejectedCallback) { + uiContext.rejectedCallback(); + } + ui_idle_flow(); +} + +static void display_cancel_status(void) { + ui_idle(); + + if (uiContext.rejectedStatus) { + nbgl_useCaseStatus(uiContext.rejectedStatus, false, cancellation_status_callback); + } else { + nbgl_useCaseStatus((char *)"Action rejected", false, cancellation_status_callback); + } +} + +static void _display_page(void) { + TRACE("_page"); + + release_context(); + + for (uint8_t i = 0; i < uiContext.currentElementCount; i++) { + tagValues[i].item = uiContext.tagTitle[i]; + tagValues[i].value = uiContext.tagContent[i]; + } + + nbgl_pageNavigationInfo_t info = { + .activePage = 0, + .nbPages = 0, + .navType = NAV_WITH_TAP, + .progressIndicator = true, + .navWithTap.backButton = false, + .navWithTap.nextPageText = (char *)"Tap to continue", + .navWithTap.nextPageToken = ACCEPT_PAGE_TOKEN, + .navWithTap.quitText = (char *)"Cancel", + .quitToken = CANCEL_PROMPT_TOKEN, + .tuneId = TUNE_TAP_CASUAL}; + + nbgl_pageContent_t content = { + .type = TAG_VALUE_LIST, + .tagValueList.nbPairs = uiContext.currentElementCount, + .tagValueList.pairs = (nbgl_layoutTagValue_t *)tagValues}; + + pageContext = nbgl_pageDrawGenericContent(&display_callback, &info, &content); + reset_transaction_current_context(); + +#ifdef HEADLESS + nbgl_refresh(); + trigger_callback(uiContext.approvedCallback); +#endif +} + +static void _display_prompt(void) { + TRACE("_prompt"); + + nbgl_useCaseReviewStart(&C_cardano_64, uiContext.pageText[0], + uiContext.pageText[1], (char *)"Reject if not sure", + uiContext.approvedCallback, &display_cancel); +#ifdef HEADLESS + nbgl_refresh(); + trigger_callback(uiContext.approvedCallback); +#endif +} + +static void _display_warning(void) { + TRACE("_warning"); + + nbgl_useCaseReviewStart(&C_warning64px, (char *)"WARNING", + uiContext.pageText[0], (char *)"Reject if not sure", + uiContext.approvedCallback, &display_cancel); +#ifdef HEADLESS + nbgl_refresh(); + trigger_callback(uiContext.approvedCallback); +#endif +} + +static void confirmation_status_callback(void) { + if (uiContext.confirmedStatus) { + nbgl_useCaseStatus(uiContext.confirmedStatus, true, ui_idle_flow); + } else { + nbgl_useCaseStatus((char *)"ACTION\nCONFIRMED", true, ui_idle_flow); + } + +} + +static void display_confirmation_status(void) { + if (uiContext.approvedCallback) { + uiContext.approvedCallback(); + } + + trigger_callback(&confirmation_status_callback); +} + +static void display_address_callback(void) { + uint8_t address_index = 0; + + // Address field is not displayed in pairList, so there is one element less. + uiContext.pairList.nbPairs = uiContext.currentElementCount - 1; + uiContext.pairList.pairs = tagValues; + + uiContext.confirmedStatus = (char *)"ADDRESS\nVERIFIED"; + uiContext.rejectedStatus = (char *)"Address rejected"; + + for (uint8_t i = 0; i < uiContext.currentElementCount; i++) { + if (strcmp(uiContext.tagTitle[i], "Address")) { + tagValues[i].item = uiContext.tagTitle[i]; + tagValues[i].value = uiContext.tagContent[i]; + } + else { + address_index = i; + } + } + + nbgl_useCaseAddressConfirmationExt(uiContext.tagContent[address_index], light_confirm_callback, &uiContext.pairList); + reset_transaction_current_context(); + +#ifdef HEADLESS + nbgl_refresh(); + trigger_callback(&display_confirmation_status); +#endif +} + +static void trigger_callback(callback_t userAcceptCallback) { + // Hack to trigger a callback from NBGL while leaving the screen untouched + nbgl_layoutDescription_t layoutDescription; + nbgl_layout_t *layout = NULL; + nbgl_layoutCenteredInfo_t centeredInfo = { + .text1 = NULL, + .text2 = NULL, + .text3 = NULL, + .style = 0, + .icon = NULL, + .offsetY = 0 + }; + + release_context(); + + layoutDescription.modal = false; + layoutDescription.withLeftBorder = true; + + layoutDescription.onActionCallback = NULL; + layoutDescription.tapActionText = (char *)""; + layoutDescription.tapActionToken = 0; + layoutDescription.tapTuneId = TUNE_TAP_CASUAL; + + layoutDescription.ticker.tickerCallback = userAcceptCallback; + layoutDescription.ticker.tickerIntervale = 0; + layoutDescription.ticker.tickerValue = 100; + pageContext = nbgl_layoutGet(&layoutDescription); + + nbgl_layoutAddCenteredInfo(layout, ¢eredInfo); +} + +static void handle_pending_element(void) { + TRACE("Add pending element"); + ASSERT(uiContext.currentElementCount == 0); + ASSERT(uiContext.currentLineCount == 0); + + fill_current_element(uiContext.tagTitle[PENDING_ELEMENT_INDEX], uiContext.tagContent[PENDING_ELEMENT_INDEX]); + + uiContext.pendingElement = false; +} + +static void _display_page_or_call_function(callback_t displayPageFn) { + if (uiContext.pendingElement) { + handle_pending_element(); + } + + if (uiContext.currentElementCount > 0) { + // We were request to display a page using displayPageFn and then call + // specific callbacks. However we have pending elements to display first. + // Therefore, temporally save displayPageFn in pendingDisplayPageFn and + // display these pending elements. + // Once these pending elements page is approved, the generic display_callback() + // function will be called, and it will then execute the function stored + // in pendingDisplayPageFn instead of the approvedCallback. + // therefore our screen will be displayed, and if it is approved, at this moment + // the approvedCallback will be called. + uiContext.pendingDisplayPageFn = displayPageFn; + _display_page(); + } else { + displayPageFn(); + } +} + +// Fillers +void force_display(callback_t userAcceptCallback, callback_t userRejectCallback) { + if (uiContext.currentLineCount > 0) { + TRACE("Force page display"); + set_callbacks(userAcceptCallback, userRejectCallback); + _display_page(); + } else { + TRACE("Nothing to do"); + trigger_callback(userAcceptCallback); + } +} + +void fill_and_display_if_required(const char *line1, const char *line2, + callback_t userAcceptCallback, + callback_t userRejectCallback) { + + ASSERT(strlen(line1) <= MAX_TAG_TITLE_LINE_LENGTH); + ASSERT(strlen(line2) <= MAX_TAG_CONTENT_LENGTH); + + if (uiContext.pendingElement) { + handle_pending_element(); + } + + if (uiContext.currentLineCount + get_element_line_count(line2) > + MAX_LINE_PER_PAGE_COUNT) { + TRACE("Display page and add pending element"); + fill_pending_element(line1, line2); + set_callbacks(userAcceptCallback, userRejectCallback); + _display_page(); + } else { + TRACE("Add element to page"); + fill_current_element(line1, line2); + trigger_callback(userAcceptCallback); + } +} + +void fill_and_display_new_page(const char *line1, const char *line2, + callback_t userAcceptCallback, + callback_t userRejectCallback) { + + ASSERT(strlen(line1) <= MAX_TAG_TITLE_LINE_LENGTH); + ASSERT(strlen(line2) <= MAX_TAG_CONTENT_LENGTH); + + if (uiContext.pendingElement) { + handle_pending_element(); + } + + if (uiContext.currentLineCount > 0) { + TRACE("Display page and add pending element"); + fill_pending_element(line1, line2); + + display_page(userAcceptCallback, userRejectCallback); + } else { + TRACE("Add element to page"); + fill_current_element(line1, line2); + uiContext.currentLineCount += get_element_line_count(line2); + display_continue(userAcceptCallback); + } +} + +void fill_address_data(char *text, char *content) { + fill_current_element(text, content); +} + +void display_confirmation(const char *text1, const char *text2, + const char *confirmText, const char *rejectText, + callback_t userAcceptCallback, + callback_t userRejectCallback) { + TRACE("Displaying confirmation"); + + uiContext.confirmedStatus = (char *)confirmText; + uiContext.rejectedStatus = (char *)rejectText; + + set_callbacks(userAcceptCallback, userRejectCallback); + + strncpy(uiContext.pageText[0], text1, MAX_TEXT_STRING); + strncpy(uiContext.pageText[1], text2, MAX_TEXT_STRING); + + if (uiContext.lightConfirmation) { + _display_page_or_call_function(&_display_light_confirmation); + } else { + _display_page_or_call_function(&_display_confirmation); + } +} + +void display_prompt(const char *text1, const char *text2, + callback_t userAcceptCallback, callback_t userRejectCallback) { + TRACE("Displaying Prompt"); + + set_callbacks(userAcceptCallback, userRejectCallback); + + strncpy(uiContext.pageText[0], text1, MAX_TEXT_STRING); + strncpy(uiContext.pageText[1], text2, MAX_TEXT_STRING); + + _display_page_or_call_function(&_display_prompt); +} + +void display_warning(const char *text, callback_t userAcceptCallback, + callback_t userRejectCallback) { + TRACE("Displaying Warning"); + + set_callbacks(userAcceptCallback, userRejectCallback); + strncpy(uiContext.pageText[0], text, MAX_TEXT_STRING); + _display_page_or_call_function(&_display_warning); +} + +void display_address(callback_t userAcceptCallback, callback_t userRejectCallback) { + TRACE("Displaying Address"); + + set_callbacks(userAcceptCallback, userRejectCallback); + nbgl_useCaseReviewStart(&C_cardano_64, (char *)"Verify Cardano\naddress", + NULL, (char *)"Cancel", display_address_callback, + display_cancel_status); +#ifdef HEADLESS + nbgl_refresh(); + trigger_callback(&display_address_callback); +#endif +} + +void display_error(void) { + TRACE("Displaying Error"); + + nbgl_reset_transaction_full_context(); + nbgl_useCaseStatus((char *)"An error has occurred", false, ui_idle_flow); +} + +#endif // HAVE_NBGL From 54e7320eaff27181ccfe7872e88d4a50a9b99c59 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 21 Oct 2022 14:58:22 +0200 Subject: [PATCH 010/105] bech32: move defines in header file --- src/bech32.h | 4 ++++ src/uiScreens.c | 3 --- src/uiScreens.h | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/bech32.h b/src/bech32.h index 562c488c..16ceb881 100644 --- a/src/bech32.h +++ b/src/bech32.h @@ -4,6 +4,10 @@ #include #include + +#define BECH32_BUFFER_SIZE_MAX 150 +#define BECH32_PREFIX_LENGTH_MAX 16 + /* * Encode bytes, using human-readable prefix given in hrp. * diff --git a/src/uiScreens.c b/src/uiScreens.c index d2e53066..24057d84 100644 --- a/src/uiScreens.c +++ b/src/uiScreens.c @@ -9,9 +9,6 @@ #include "tokens.h" -#define BECH32_BUFFER_SIZE_MAX 150 -#define BECH32_PREFIX_LENGTH_MAX 16 - // encodes a buffer into bech32 and displays it (works for bufferSize <= 150 and prefix length <= 12) void ui_displayBech32Screen( const char* firstLine, diff --git a/src/uiScreens.h b/src/uiScreens.h index c13cd097..83047e73 100644 --- a/src/uiScreens.h +++ b/src/uiScreens.h @@ -6,6 +6,7 @@ #include "signTx.h" #include "signTxOutput.h" #include "signTxPoolRegistration.h" +#include "bech32.h" __noinline_due_to_stack__ void ui_displayBech32Screen( From 476178ceee0a41f05a73b31a481a6222f8edc7fc Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 24 Oct 2022 10:25:14 +0200 Subject: [PATCH 011/105] tokens_test: update for stax --- src/tokens_test.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tokens_test.c b/src/tokens_test.c index c78be646..4abd3860 100644 --- a/src/tokens_test.c +++ b/src/tokens_test.c @@ -5,7 +5,12 @@ #include "hexUtils.h" #include "testUtils.h" #include "tokens.h" -#include "uiScreens.h" + +#ifdef HAVE_BAGL +#include "uiScreens_bagl.h" +#elif defined(HAVE_NBGL) +#include "uiScreens_nbgl.h" +#endif void testcase_assetFingerprint( const char* policyIdHex, From 721f9adeaf84a7309f05ea6aa8ad408d36a24071 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 27 Dec 2022 09:48:24 +0100 Subject: [PATCH 012/105] Fix stax not locked on usb connection in app --- src/io.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/io.c b/src/io.c index e3cd3775..bd6fd860 100644 --- a/src/io.c +++ b/src/io.c @@ -106,6 +106,9 @@ unsigned char io_event(unsigned char channel MARK_UNUSED) case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: #ifdef HAVE_BAGL UX_DISPLAYED_EVENT({}); +#endif +#ifdef HAVE_NBGL + UX_DEFAULT_EVENT(); #endif break; From 82fadeece658e75c559b5b034535f327e866889f Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 14 Mar 2023 16:17:44 +0100 Subject: [PATCH 013/105] signTx: update for stax --- src/signTx.c | 735 +----------------------------------- src/signTx.h | 3 + src/signTxUtils.c | 9 + src/signTx_ui.c | 938 ++++++++++++++++++++++++++++++++++++++++++++++ src/signTx_ui.h | 163 ++++++++ 5 files changed, 1124 insertions(+), 724 deletions(-) create mode 100644 src/signTx_ui.c create mode 100644 src/signTx_ui.h diff --git a/src/signTx.c b/src/signTx.c index bee1171c..cacf0bd7 100644 --- a/src/signTx.c +++ b/src/signTx.c @@ -7,7 +7,6 @@ #include "addressUtilsShelley.h" #include "uiHelpers.h" #include "signTxUtils.h" -#include "uiScreens.h" #include "txHashBuilder.h" #include "textUtils.h" #include "hexUtils.h" @@ -15,6 +14,7 @@ #include "messageSigning.h" #include "bufView.h" #include "securityPolicy.h" +#include "signTx_ui.h" static ins_sign_tx_context_t* ctx = &(instructionState.signTxContext); @@ -58,7 +58,7 @@ static inline void initTxWitnessCtx() } // advances the stage of the main state machine -static inline void advanceStage() +void tx_advanceStage() { TRACE("Advancing sign tx stage from: %d", ctx->stage); @@ -292,7 +292,7 @@ static inline void advanceStage() break; case SIGN_STAGE_NONE: - // advanceStage() not supposed to be called after tx processing is finished + // tx_advanceStage() not supposed to be called after tx processing is finished ASSERT(false); default: @@ -318,7 +318,7 @@ static inline void advanceCertificatesStateIfAppropriate() BODY_CTX->currentCertificate++; if (BODY_CTX->currentCertificate == ctx->numCertificates) { - advanceStage(); + tx_advanceStage(); } } break; @@ -350,7 +350,7 @@ static inline void checkForFinishedSubmachines() BODY_CTX->currentOutput++; if (BODY_CTX->currentOutput == ctx->numOutputs) { - advanceStage(); + tx_advanceStage(); } } break; @@ -375,7 +375,7 @@ static inline void checkForFinishedSubmachines() STATIC_ASSERT(SIZEOF(AUX_DATA_CTX->stageContext.cvote_registration_subctx.auxDataHash) == AUX_DATA_HASH_LENGTH, "Wrong auxiliary data hash length"); memmove(ctx->auxDataHash, AUX_DATA_CTX->stageContext.cvote_registration_subctx.auxDataHash, AUX_DATA_HASH_LENGTH); - advanceStage(); + tx_advanceStage(); } break; @@ -384,7 +384,7 @@ static inline void checkForFinishedSubmachines() TRACE(); ctx->stage = SIGN_STAGE_BODY_MINT; BODY_CTX->mintReceived = true; - advanceStage(); + tx_advanceStage(); } case SIGN_STAGE_BODY_COLLATERAL_OUTPUT_SUBMACHINE: @@ -392,7 +392,7 @@ static inline void checkForFinishedSubmachines() TRACE(); ctx->stage = SIGN_STAGE_BODY_COLLATERAL_OUTPUT; BODY_CTX->collateralOutputReceived = true; - advanceStage(); + tx_advanceStage(); } break; @@ -410,119 +410,6 @@ static inline void CHECK_STAGE(sign_tx_stage_t expected) // ============================== INIT ============================== -enum { - HANDLE_INIT_STEP_PROMPT_SIGNINGMODE = 100, - HANDLE_INIT_STEP_DISPLAY_NETWORK_DETAILS, - HANDLE_INIT_STEP_SCRIPT_RUNNING_WARNING, - HANDLE_INIT_STEP_NO_COLLATERAL_WARNING, - HANDLE_INIT_STEP_UNKNOWN_COLLATERAL_WARNING, - HANDLE_INIT_STEP_NO_SCRIPT_DATA_HASH_WARNING, - HANDLE_INIT_STEP_RESPOND, - HANDLE_INIT_STEP_INVALID, -} ; - -static const char* _newTxLine1(sign_tx_signingmode_t txSigningMode) -{ - switch (txSigningMode) { - - case SIGN_TX_SIGNINGMODE_ORDINARY_TX: - return "New ordinary"; - - case SIGN_TX_SIGNINGMODE_POOL_REGISTRATION_OWNER: - return "New pool owner"; - - case SIGN_TX_SIGNINGMODE_POOL_REGISTRATION_OPERATOR: - return "New pool operator"; - - case SIGN_TX_SIGNINGMODE_MULTISIG_TX: - return "New multisig"; - - case SIGN_TX_SIGNINGMODE_PLUTUS_TX: - return "New Plutus"; - - default: - ASSERT(false); - } -} - -static void signTx_handleInit_ui_runStep() -{ - TRACE("UI step %d", ctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTx_handleInit_ui_runStep; - - UI_STEP_BEGIN(ctx->ui_step, this_fn); - - UI_STEP(HANDLE_INIT_STEP_PROMPT_SIGNINGMODE) { - ui_displayPrompt( - _newTxLine1(ctx->commonTxData.txSigningMode), - "transaction?", - this_fn, - respond_with_user_reject - ); - } - - UI_STEP(HANDLE_INIT_STEP_DISPLAY_NETWORK_DETAILS) { - const bool isNetworkIdVerifiable = isTxNetworkIdVerifiable( - ctx->includeNetworkId, - ctx->numOutputs, ctx->numWithdrawals, - ctx->commonTxData.txSigningMode - ); - if (isNetworkIdVerifiable) { - if (isNetworkUsual(ctx->commonTxData.networkId, ctx->commonTxData.protocolMagic)) { - // no need to display the network details - UI_STEP_JUMP(HANDLE_INIT_STEP_SCRIPT_RUNNING_WARNING); - } - ui_displayNetworkParamsScreen( - "Network details", - ctx->commonTxData.networkId, ctx->commonTxData.protocolMagic, - this_fn - ); - } else { - // technically, no pool reg. certificate as well, but the UI message would be too long - ui_displayPaginatedText( - "Warning:", - "cannot verify network id: no outputs or withdrawals", - this_fn - ); - } - } - - UI_STEP(HANDLE_INIT_STEP_SCRIPT_RUNNING_WARNING) { - if (!needsRunningScriptWarning(ctx->numCollateralInputs)) { - UI_STEP_JUMP(HANDLE_INIT_STEP_NO_COLLATERAL_WARNING); - } - ui_displayPaginatedText("WARNING:", "Plutus script will be evaluated", this_fn); - } - - UI_STEP(HANDLE_INIT_STEP_NO_COLLATERAL_WARNING) { - if (!needsMissingCollateralWarning(ctx->commonTxData.txSigningMode, ctx->numCollateralInputs)) { - UI_STEP_JUMP(HANDLE_INIT_STEP_NO_SCRIPT_DATA_HASH_WARNING); - } - ui_displayPaginatedText("WARNING:", "No collateral given for Plutus transaction", this_fn); - } - - UI_STEP(HANDLE_INIT_STEP_UNKNOWN_COLLATERAL_WARNING) { - if (!needsUnknownCollateralWarning(ctx->commonTxData.txSigningMode, ctx->includeTotalCollateral)) { - UI_STEP_JUMP(HANDLE_INIT_STEP_NO_SCRIPT_DATA_HASH_WARNING); - } - ui_displayPaginatedText("WARNING:", "Unknown collateral amount", this_fn); - } - - UI_STEP(HANDLE_INIT_STEP_NO_SCRIPT_DATA_HASH_WARNING) { - if (!needsMissingScriptDataHashWarning(ctx->commonTxData.txSigningMode, ctx->includeScriptDataHash)) { - UI_STEP_JUMP(HANDLE_INIT_STEP_RESPOND); - } - ui_displayPaginatedText("WARNING:", "No script data given for Plutus transaction", this_fn); - } - - UI_STEP(HANDLE_INIT_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceStage(); - } - UI_STEP_END(HANDLE_INIT_STEP_INVALID); -} - __noinline_due_to_stack__ static void signTx_handleInitAPDU(uint8_t p2, const uint8_t* wireDataBuffer, size_t wireDataSize) { @@ -695,66 +582,6 @@ static void signTx_handleInitAPDU(uint8_t p2, const uint8_t* wireDataBuffer, siz // ============================== AUXILIARY DATA ============================== -enum { - HANDLE_AUX_DATA_ARBITRARY_HASH_STEP_DISPLAY = 800, - HANDLE_AUX_DATA_ARBITRARY_HASH_STEP_RESPOND, - HANDLE_AUX_DATA_ARBITRARY_HASH_STEP_INVALID, -}; - -static void signTx_handleAuxDataArbitraryHash_ui_runStep() -{ - TRACE("UI step %d", ctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTx_handleAuxDataArbitraryHash_ui_runStep; - - UI_STEP_BEGIN(ctx->ui_step, this_fn); - - UI_STEP(HANDLE_AUX_DATA_ARBITRARY_HASH_STEP_DISPLAY) { - ui_displayHexBufferScreen( - "Auxiliary data hash", - ctx->auxDataHash, - SIZEOF(ctx->auxDataHash), - this_fn - ); - } - UI_STEP(HANDLE_AUX_DATA_ARBITRARY_HASH_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceStage(); - } - UI_STEP_END(HANDLE_AUX_DATA_ARBITRARY_HASH_STEP_INVALID); -} - - -enum { - HANDLE_AUX_DATA_CVOTE_REGISTRATION_STEP_DISPLAY = 850, - HANDLE_AUX_DATA_CVOTE_REGISTRATION_STEP_RESPOND, - HANDLE_AUX_DATA_CVOTE_REGISTRATION_STEP_INVALID, -}; - -static void signTx_handleAuxDataCVoteRegistration_ui_runStep() -{ - TRACE("UI step %d", ctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTx_handleAuxDataCVoteRegistration_ui_runStep; - - UI_STEP_BEGIN(ctx->ui_step, this_fn); - - UI_STEP(HANDLE_AUX_DATA_CVOTE_REGISTRATION_STEP_DISPLAY) { - ui_displayPrompt( - "Register vote", - "key (CIP-36)?", - this_fn, - respond_with_user_reject - ); - } - UI_STEP(HANDLE_AUX_DATA_CVOTE_REGISTRATION_STEP_RESPOND) { - respondSuccessEmptyMsg(); - signTxCVoteRegistration_init(); - ctx->stage = SIGN_STAGE_AUX_DATA_CVOTE_REGISTRATION_SUBMACHINE; - } - UI_STEP_END(HANDLE_AUX_DATA_CVOTE_REGISTRATION_STEP_INVALID); -} - __noinline_due_to_stack__ static void signTx_handleAuxDataAPDU(uint8_t p2, const uint8_t* wireDataBuffer, size_t wireDataSize) { @@ -843,32 +670,6 @@ static void signTx_handleAuxDataAPDU(uint8_t p2, const uint8_t* wireDataBuffer, // ============================== INPUTS ============================== -enum { - HANDLE_INPUT_STEP_DISPLAY = 200, - HANDLE_INPUT_STEP_RESPOND, - HANDLE_INPUT_STEP_INVALID, -}; - -static void signTx_handleInput_ui_runStep() -{ - TRACE("UI step %d", ctx->ui_step); - ui_callback_fn_t* this_fn = signTx_handleInput_ui_runStep; - - UI_STEP_BEGIN(ctx->ui_step, this_fn); - - UI_STEP(HANDLE_INPUT_STEP_DISPLAY) { - ui_displayInputScreen(&BODY_CTX->stageData.input, this_fn); - } - - UI_STEP(HANDLE_INPUT_STEP_RESPOND) { - respondSuccessEmptyMsg(); - - ASSERT(ctx->ui_advanceState != NULL); - ctx->ui_advanceState(); - } - UI_STEP_END(HANDLE_INPUT_STEP_INVALID); -} - // Advance stage to the next input static void ui_advanceState_input() { @@ -876,7 +677,7 @@ static void ui_advanceState_input() BODY_CTX->currentInput++; if (BODY_CTX->currentInput == ctx->numInputs) { - advanceStage(); + tx_advanceStage(); } } @@ -985,31 +786,6 @@ static void signTx_handleOutputAPDU(uint8_t p2, const uint8_t* wireDataBuffer, s // ============================== FEE ============================== -enum { - HANDLE_FEE_STEP_DISPLAY = 400, - HANDLE_FEE_STEP_RESPOND, - HANDLE_FEE_STEP_INVALID, -}; - -static void signTx_handleFee_ui_runStep() -{ - TRACE("UI step %d", ctx->ui_step); - ui_callback_fn_t* this_fn = signTx_handleFee_ui_runStep; - - TRACE_ADA_AMOUNT("fee ", BODY_CTX->stageData.fee); - - UI_STEP_BEGIN(ctx->ui_step, this_fn); - - UI_STEP(HANDLE_FEE_STEP_DISPLAY) { - ui_displayAdaAmountScreen("Transaction fee", BODY_CTX->stageData.fee, this_fn); - } - UI_STEP(HANDLE_FEE_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceStage(); - } - UI_STEP_END(HANDLE_FEE_STEP_INVALID); -} - __noinline_due_to_stack__ static void signTx_handleFeeAPDU(uint8_t p2, const uint8_t* wireDataBuffer, size_t wireDataSize) { @@ -1057,34 +833,6 @@ static void signTx_handleFeeAPDU(uint8_t p2, const uint8_t* wireDataBuffer, size // ============================== TTL ============================== -enum { - HANDLE_TTL_STEP_DISPLAY = 500, - HANDLE_TTL_STEP_RESPOND, - HANDLE_TTL_STEP_INVALID, -}; - -static void signTx_handleTtl_ui_runStep() -{ - TRACE("UI step %d", ctx->ui_step); - ui_callback_fn_t* this_fn = signTx_handleTtl_ui_runStep; - - UI_STEP_BEGIN(ctx->ui_step, this_fn); - - UI_STEP(HANDLE_TTL_STEP_DISPLAY) { - ui_displayValidityBoundaryScreen( - "Transaction TTL", - BODY_CTX->stageData.ttl, - ctx->commonTxData.networkId, ctx->commonTxData.protocolMagic, - this_fn - ); - } - UI_STEP(HANDLE_TTL_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceStage(); - } - UI_STEP_END(HANDLE_TTL_STEP_INVALID); -} - __noinline_due_to_stack__ static void signTx_handleTtlAPDU(uint8_t p2, const uint8_t* wireDataBuffer, size_t wireDataSize) { @@ -1133,173 +881,6 @@ static void signTx_handleTtlAPDU(uint8_t p2, const uint8_t* wireDataBuffer, size // ============================== CERTIFICATES ============================== -enum { - HANDLE_CERTIFICATE_STEP_DISPLAY_OPERATION = 600, - HANDLE_CERTIFICATE_STEP_DISPLAY_STAKING_KEY, - HANDLE_CERTIFICATE_STEP_CONFIRM, - HANDLE_CERTIFICATE_STEP_RESPOND, - HANDLE_CERTIFICATE_STEP_INVALID, -}; - -static void signTx_handleCertificate_ui_runStep() -{ - TRACE("UI step %d", ctx->ui_step); - ui_callback_fn_t* this_fn = signTx_handleCertificate_ui_runStep; - - UI_STEP_BEGIN(ctx->ui_step, this_fn); - - UI_STEP(HANDLE_CERTIFICATE_STEP_DISPLAY_OPERATION) { - switch (BODY_CTX->stageData.certificate.type) { - case CERTIFICATE_TYPE_STAKE_REGISTRATION: - ui_displayPaginatedText( - "Register", - "staking key", - this_fn - ); - break; - - case CERTIFICATE_TYPE_STAKE_DEREGISTRATION: - ui_displayPaginatedText( - "Deregister", - "staking key", - this_fn - ); - break; - - case CERTIFICATE_TYPE_STAKE_DELEGATION: - ui_displayBech32Screen( - "Delegate stake to", - "pool", - BODY_CTX->stageData.certificate.poolKeyHash, SIZEOF(BODY_CTX->stageData.certificate.poolKeyHash), - this_fn - ); - break; - - default: - // includes CERTIFICATE_TYPE_STAKE_POOL_REGISTRATION - // and CERTIFICATE_TYPE_STAKE_POOL_RETIREMENT - // which have separate UI; this handler must not be used - ASSERT(false); - } - } - UI_STEP(HANDLE_CERTIFICATE_STEP_DISPLAY_STAKING_KEY) { - switch (BODY_CTX->stageData.certificate.stakeCredential.type) { - case STAKE_CREDENTIAL_KEY_PATH: - ui_displayPathScreen( - "Staking key", - &BODY_CTX->stageData.certificate.stakeCredential.keyPath, - this_fn - ); - break; - case STAKE_CREDENTIAL_KEY_HASH: - ui_displayBech32Screen( - "Staking key hash", - "stake_vkh", - BODY_CTX->stageData.certificate.stakeCredential.keyHash, - SIZEOF(BODY_CTX->stageData.certificate.stakeCredential.keyHash), - this_fn - ); - break; - case STAKE_CREDENTIAL_SCRIPT_HASH: - ui_displayBech32Screen( - "Staking script hash", - "script", - BODY_CTX->stageData.certificate.stakeCredential.scriptHash, - SIZEOF(BODY_CTX->stageData.certificate.stakeCredential.scriptHash), - this_fn - ); - break; - default: - ASSERT(false); - break; - } - } - UI_STEP(HANDLE_CERTIFICATE_STEP_CONFIRM) { - char description[50] = {0}; - explicit_bzero(description, SIZEOF(description)); - - switch (BODY_CTX->stageData.certificate.type) { - case CERTIFICATE_TYPE_STAKE_REGISTRATION: - snprintf(description, SIZEOF(description), "registration?"); - break; - - case CERTIFICATE_TYPE_STAKE_DEREGISTRATION: - snprintf(description, SIZEOF(description), "deregistration?"); - break; - - case CERTIFICATE_TYPE_STAKE_DELEGATION: - snprintf(description, SIZEOF(description), "delegation?"); - break; - - default: - ASSERT(false); - } - // make sure all the information is displayed to the user - ASSERT(strlen(description) + 1 < SIZEOF(description)); - - ui_displayPrompt( - "Confirm", - description, - this_fn, - respond_with_user_reject - ); - } - UI_STEP(HANDLE_CERTIFICATE_STEP_RESPOND) { - respondSuccessEmptyMsg(); - - advanceCertificatesStateIfAppropriate(); - } - UI_STEP_END(HANDLE_CERTIFICATE_STEP_INVALID); -} - -enum { - HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_DISPLAY_OPERATION = 650, - HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_DISPLAY_EPOCH, - HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_CONFIRM, - HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_RESPOND, - HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_INVALID, -}; - -static void signTx_handleCertificatePoolRetirement_ui_runStep() -{ - TRACE("UI step %d", ctx->ui_step); - ASSERT(BODY_CTX->stageData.certificate.type == CERTIFICATE_TYPE_STAKE_POOL_RETIREMENT); - - ui_callback_fn_t* this_fn = signTx_handleCertificatePoolRetirement_ui_runStep; - - UI_STEP_BEGIN(ctx->ui_step, this_fn); - - UI_STEP(HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_DISPLAY_OPERATION) { - ui_displayBech32Screen( - "Retire stake pool", - "pool", - BODY_CTX->stageData.certificate.poolKeyHash, SIZEOF(BODY_CTX->stageData.certificate.poolKeyHash), - this_fn - ); - } - UI_STEP(HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_DISPLAY_EPOCH) { - ui_displayUint64Screen( - "at the start of epoch", - BODY_CTX->stageData.certificate.epoch, - this_fn - ); - } - UI_STEP(HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_CONFIRM) { - ui_displayPrompt( - "Confirm", - "pool retirement", - this_fn, - respond_with_user_reject - ); - } - UI_STEP(HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_RESPOND) { - respondSuccessEmptyMsg(); - - advanceCertificatesStateIfAppropriate(); - } - UI_STEP_END(HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_INVALID); -} - static void _parsePathSpec(read_view_t* view, bip44_path_t* pathSpec) { view_skipBytes(view, bip44_parseFromWire(pathSpec, VIEW_REMAINING_TO_TUPLE_BUF_SIZE(view))); @@ -1567,76 +1148,6 @@ static void signTx_handleCertificateAPDU(uint8_t p2, const uint8_t* wireDataBuff // ============================== WITHDRAWALS ============================== -enum { - HANDLE_WITHDRAWAL_STEP_DISPLAY_AMOUNT = 700, - HANDLE_WITHDRAWAL_STEP_DISPLAY_PATH, - HANDLE_WITHDRAWAL_STEP_RESPOND, - HANDLE_WITHDRAWAL_STEP_INVALID, -}; - -static void signTx_handleWithdrawal_ui_runStep() -{ - TRACE("UI step %d", ctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTx_handleWithdrawal_ui_runStep; - - UI_STEP_BEGIN(ctx->ui_step, this_fn); - - UI_STEP(HANDLE_WITHDRAWAL_STEP_DISPLAY_AMOUNT) { - ui_displayAdaAmountScreen("Withdrawing rewards", BODY_CTX->stageData.withdrawal.amount, this_fn); - } - UI_STEP(HANDLE_WITHDRAWAL_STEP_DISPLAY_PATH) { - reward_account_t rewardAccount; - switch (BODY_CTX->stageData.withdrawal.stakeCredential.type) { - case STAKE_CREDENTIAL_KEY_PATH: { - rewardAccount.keyReferenceType = KEY_REFERENCE_PATH; - rewardAccount.path = BODY_CTX->stageData.withdrawal.stakeCredential.keyPath; - break; - } - case STAKE_CREDENTIAL_KEY_HASH: { - rewardAccount.keyReferenceType = KEY_REFERENCE_HASH; - constructRewardAddressFromHash( - ctx->commonTxData.networkId, - REWARD_HASH_SOURCE_KEY, - BODY_CTX->stageData.withdrawal.stakeCredential.keyHash, - SIZEOF(BODY_CTX->stageData.withdrawal.stakeCredential.keyHash), - rewardAccount.hashBuffer, - SIZEOF(rewardAccount.hashBuffer) - ); - break; - } - case STAKE_CREDENTIAL_SCRIPT_HASH: { - rewardAccount.keyReferenceType = KEY_REFERENCE_HASH; - constructRewardAddressFromHash( - ctx->commonTxData.networkId, - REWARD_HASH_SOURCE_SCRIPT, - BODY_CTX->stageData.withdrawal.stakeCredential.scriptHash, - SIZEOF(BODY_CTX->stageData.withdrawal.stakeCredential.scriptHash), - rewardAccount.hashBuffer, - SIZEOF(rewardAccount.hashBuffer) - ); - break; - } - default: - ASSERT(false); - break; - } - ui_displayRewardAccountScreen(&rewardAccount, ctx->commonTxData.networkId, this_fn); - } - UI_STEP(HANDLE_WITHDRAWAL_STEP_RESPOND) { - respondSuccessEmptyMsg(); - - // Advance stage to the next withdrawal - ASSERT(BODY_CTX->currentWithdrawal < ctx->numWithdrawals); - BODY_CTX->currentWithdrawal++; - - if (BODY_CTX->currentWithdrawal == ctx->numWithdrawals) { - advanceStage(); - } - } - UI_STEP_END(HANDLE_WITHDRAWAL_STEP_INVALID); -} - __noinline_due_to_stack__ static void _addWithdrawalToTxHash(bool validateCanonicalOrdering) { @@ -1755,34 +1266,6 @@ static void signTx_handleWithdrawalAPDU(uint8_t p2, const uint8_t* wireDataBuffe // ============================== VALIDITY INTERVAL START ============================== -enum { - HANDLE_VALIDITY_INTERVAL_START_STEP_DISPLAY = 900, - HANDLE_VALIDITY_INTERVAL_START_STEP_RESPOND, - HANDLE_VALIDITY_INTERVAL_START_STEP_INVALID, -}; - -static void signTx_handleValidityInterval_ui_runStep() -{ - TRACE("UI step %d", ctx->ui_step); - ui_callback_fn_t* this_fn = signTx_handleValidityInterval_ui_runStep; - - UI_STEP_BEGIN(ctx->ui_step, this_fn); - - UI_STEP(HANDLE_VALIDITY_INTERVAL_START_STEP_DISPLAY) { - ui_displayValidityBoundaryScreen( - "Validity interval start", - BODY_CTX->stageData.validityIntervalStart, - ctx->commonTxData.networkId, ctx->commonTxData.protocolMagic, - this_fn - ); - } - UI_STEP(HANDLE_VALIDITY_INTERVAL_START_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceStage(); - } - UI_STEP_END(HANDLE_VALIDITY_INTERVAL_START_STEP_INVALID); -} - static void signTx_handleValidityIntervalStartAPDU(uint8_t p2, const uint8_t* wireDataBuffer, size_t wireDataSize) { { @@ -1854,35 +1337,6 @@ static void signTx_handleMintAPDU(uint8_t p2, const uint8_t* wireDataBuffer, siz // ========================= SCRIPT DATA HASH ========================== - -enum { - HANDLE_SCRIPT_DATA_HASH_STEP_DISPLAY = 1200, - HANDLE_SCRIPT_DATA_HASH_STEP_RESPOND, - HANDLE_SCRIPT_DATA_HASH_STEP_INVALID, -}; - -static void signTx_handleScriptDataHash_ui_runStep() -{ - TRACE("UI step %d", ctx->ui_step); - ui_callback_fn_t* this_fn = signTx_handleScriptDataHash_ui_runStep; - - UI_STEP_BEGIN(ctx->ui_step, this_fn); - - UI_STEP(HANDLE_SCRIPT_DATA_HASH_STEP_DISPLAY) { - ui_displayBech32Screen( - "Script data hash", - "script_data", - BODY_CTX->stageData.scriptDataHash, SCRIPT_DATA_HASH_LENGTH, - this_fn - ); - } - UI_STEP(HANDLE_SCRIPT_DATA_HASH_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceStage(); - } - UI_STEP_END(HANDLE_FEE_STEP_INVALID); -} - static void signTx_handleScriptDataHashAPDU(uint8_t p2, const uint8_t* wireDataBuffer, size_t wireDataSize) { { @@ -1938,7 +1392,7 @@ static void ui_advanceState_collateralInput() BODY_CTX->currentCollateral++; if (BODY_CTX->currentCollateral == ctx->numCollateralInputs) { - advanceStage(); + tx_advanceStage(); } } @@ -1984,54 +1438,6 @@ static void signTx_handleCollateralInputAPDU(uint8_t p2, const uint8_t* wireData // ========================= REQUIRED SIGNERS =========================== -enum { - HANDLE_REQUIRED_SIGNERS_STEP_DISPLAY = 1400, - HANDLE_REQUIRED_SIGNERS_STEP_RESPOND, - HANDLE_REQUIRED_SIGNERS_STEP_INVALID, -}; - -static void signTx_handleRequiredSigner_ui_runStep() -{ - TRACE("UI step %d", ctx->ui_step); - ui_callback_fn_t* this_fn = signTx_handleRequiredSigner_ui_runStep; - - UI_STEP_BEGIN(ctx->ui_step, this_fn); - - UI_STEP(HANDLE_REQUIRED_SIGNERS_STEP_DISPLAY) { - switch (BODY_CTX->stageData.requiredSigner.type) { - case REQUIRED_SIGNER_WITH_PATH: - ui_displayPathScreen("Required signer", &BODY_CTX->stageData.requiredSigner.keyPath, this_fn); - break; - case REQUIRED_SIGNER_WITH_HASH: - ui_displayBech32Screen( - "Required signer", - "req_signer_vkh", - BODY_CTX->stageData.requiredSigner.keyHash, - SIZEOF(BODY_CTX->stageData.requiredSigner.keyHash), - this_fn - ); - break; - - default: - ASSERT(false); - break; - } - } - - UI_STEP(HANDLE_REQUIRED_SIGNERS_STEP_RESPOND) { - respondSuccessEmptyMsg(); - - // Advance stage to the next input - ASSERT(BODY_CTX->currentRequiredSigner < ctx->numRequiredSigners); - BODY_CTX->currentRequiredSigner++; - - if (BODY_CTX->currentRequiredSigner == ctx->numRequiredSigners) { - advanceStage(); - } - } - UI_STEP_END(HANDLE_REQUIRED_SIGNERS_STEP_INVALID); -} - __noinline_due_to_stack__ static void signTx_handleRequiredSignerAPDU(uint8_t p2, const uint8_t* wireDataBuffer, size_t wireDataSize) { @@ -2125,31 +1531,6 @@ static void signTx_handleCollateralOutputAPDU(uint8_t p2, const uint8_t* wireDat // ========================= TOTAL COLLATERAL =========================== -enum { - HANDLE_TOTAL_COLLATERAL_STEP_DISPLAY = 400, - HANDLE_TOTAL_COLLATERAL_STEP_RESPOND, - HANDLE_TOTAL_COLLATERAL_STEP_INVALID, -}; - -static void signTx_handleTotalCollateral_ui_runStep() -{ - TRACE("UI step %d", ctx->ui_step); - ui_callback_fn_t* this_fn = signTx_handleTotalCollateral_ui_runStep; - - TRACE_ADA_AMOUNT("total collateral ", BODY_CTX->stageData.totalCollateral); - - UI_STEP_BEGIN(ctx->ui_step, this_fn); - - UI_STEP(HANDLE_TOTAL_COLLATERAL_STEP_DISPLAY) { - ui_displayAdaAmountScreen("Total collateral", BODY_CTX->stageData.totalCollateral, this_fn); - } - UI_STEP(HANDLE_TOTAL_COLLATERAL_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceStage(); - } - UI_STEP_END(HANDLE_TOTAL_COLLATERAL_STEP_INVALID); -} - __noinline_due_to_stack__ static void signTx_handleTotalCollateralAPDU(uint8_t p2, const uint8_t* wireDataBuffer, size_t wireDataSize) { @@ -2206,7 +1587,7 @@ static void ui_advanceState_ReferenceInput() BODY_CTX->currentReferenceInput++; if (BODY_CTX->currentReferenceInput == ctx->numReferenceInputs) { - advanceStage(); + tx_advanceStage(); } } @@ -2249,45 +1630,6 @@ static void signTx_handleReferenceInputsAPDU(uint8_t p2, const uint8_t* wireData // ============================== CONFIRM ============================== -enum { - HANDLE_CONFIRM_STEP_TXID = 1000, - HANDLE_CONFIRM_STEP_FINAL_CONFIRM, - HANDLE_CONFIRM_STEP_RESPOND, - HANDLE_CONFIRM_STEP_INVALID, -}; - -static void signTx_handleConfirm_ui_runStep() -{ - TRACE("UI step %d", ctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTx_handleConfirm_ui_runStep; - - UI_STEP_BEGIN(ctx->ui_step, this_fn); - - UI_STEP(HANDLE_CONFIRM_STEP_TXID) { - ui_displayHexBufferScreen( - "Transaction id", - ctx->txHash, SIZEOF(ctx->txHash), - this_fn - ); - } - UI_STEP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM) { - ui_displayPrompt( - "Confirm", - "transaction?", - this_fn, - respond_with_user_reject - ); - } - UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { - io_send_buf(SUCCESS, ctx->txHash, SIZEOF(ctx->txHash)); - ui_displayBusy(); // displays dots, called only after I/O to avoid freezing - - advanceStage(); - } - UI_STEP_END(HANDLE_CONFIRM_STEP_INVALID); -} - static bool _shouldDisplayTxId(sign_tx_signingmode_t signingMode) { switch(signingMode) { @@ -2356,61 +1698,6 @@ static void signTx_handleConfirmAPDU(uint8_t p2, const uint8_t* wireDataBuffer M // ============================== WITNESS ============================== -static void _wipeWitnessSignature() -{ - // safer not to keep the signature in memory - explicit_bzero(WITNESS_CTX->stageData.witness.signature, SIZEOF(WITNESS_CTX->stageData.witness.signature)); - respond_with_user_reject(); -} - -enum { - HANDLE_WITNESS_STEP_WARNING = 1100, - HANDLE_WITNESS_STEP_DISPLAY, - HANDLE_WITNESS_STEP_CONFIRM, - HANDLE_WITNESS_STEP_RESPOND, - HANDLE_WITNESS_STEP_INVALID, -}; - -static void signTx_handleWitness_ui_runStep() -{ - TRACE("UI step %d", ctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTx_handleWitness_ui_runStep; - - UI_STEP_BEGIN(ctx->ui_step, this_fn); - - UI_STEP(HANDLE_WITNESS_STEP_WARNING) { - ui_displayPaginatedText( - "WARNING:", - "unusual witness requested", - this_fn - ); - } - UI_STEP(HANDLE_WITNESS_STEP_DISPLAY) { - ui_displayPathScreen("Witness path", &WITNESS_CTX->stageData.witness.path, this_fn); - } - UI_STEP(HANDLE_WITNESS_STEP_CONFIRM) { - ui_displayPrompt( - "Sign using", - "this witness?", - this_fn, - _wipeWitnessSignature - ); - } - UI_STEP(HANDLE_WITNESS_STEP_RESPOND) { - TRACE("Sending witness data"); - TRACE_BUFFER(WITNESS_CTX->stageData.witness.signature, SIZEOF(WITNESS_CTX->stageData.witness.signature)); - io_send_buf(SUCCESS, WITNESS_CTX->stageData.witness.signature, SIZEOF(WITNESS_CTX->stageData.witness.signature)); - ui_displayBusy(); // displays dots, called only after I/O to avoid freezing - - WITNESS_CTX->currentWitness++; - if (WITNESS_CTX->currentWitness == ctx->numWitnesses) { - advanceStage(); - } - } - UI_STEP_END(HANDLE_WITNESS_STEP_INVALID); -} - __noinline_due_to_stack__ static void signTx_handleWitnessAPDU(uint8_t p2, const uint8_t* wireDataBuffer, size_t wireDataSize) { diff --git a/src/signTx.h b/src/signTx.h index d50db9c9..288bfccc 100644 --- a/src/signTx.h +++ b/src/signTx.h @@ -252,4 +252,7 @@ static inline bool signTx_parseIncluded(uint8_t value) } } +// advances the stage of the main state machine +void tx_advanceStage(void); + #endif // H_CARDANO_APP_SIGN_TX diff --git a/src/signTxUtils.c b/src/signTxUtils.c index daca4896..f06926e0 100644 --- a/src/signTxUtils.c +++ b/src/signTxUtils.c @@ -6,11 +6,20 @@ #include "securityPolicy.h" #include "state.h" +#ifdef HAVE_BAGL +#include "uiScreens_bagl.h" +#elif defined(HAVE_NBGL) +#include "nbgl_use_case.h" +#include "uiScreens_nbgl.h" +#endif + void respondSuccessEmptyMsg() { TRACE(); io_send_buf(SUCCESS, NULL, 0); +#ifdef HAVE_BAGL ui_displayBusy(); // displays dots, called only after I/O to avoid freezing +#endif } bool violatesSingleAccountOrStoreIt(const bip44_path_t* path) diff --git a/src/signTx_ui.c b/src/signTx_ui.c new file mode 100644 index 00000000..ea5a6a7d --- /dev/null +++ b/src/signTx_ui.c @@ -0,0 +1,938 @@ +#include "app_mode.h" +#include "signTx.h" +#include "state.h" +#include "bech32.h" +#include "cardano.h" +#include "addressUtilsByron.h" +#include "addressUtilsShelley.h" +#include "uiHelpers.h" +#include "signTxUtils.h" +#include "txHashBuilder.h" +#include "textUtils.h" +#include "hexUtils.h" +#include "utils.h" +#include "messageSigning.h" +#include "bufView.h" +#include "securityPolicy.h" +#include "signTx_ui.h" + +#ifdef HAVE_BAGL +#include "uiScreens_bagl.h" +#elif defined(HAVE_NBGL) +#include "uiScreens_nbgl.h" +#include "nbgl_use_case.h" +#endif + +static ins_sign_tx_context_t* ctx = &(instructionState.signTxContext); + +// ============================== INIT ============================== + +static const char* _newTxLine1(sign_tx_signingmode_t txSigningMode) +{ + switch (txSigningMode) { + + case SIGN_TX_SIGNINGMODE_ORDINARY_TX: +#ifdef HAVE_BAGL + return "New ordinary"; +#elif defined(HAVE_NBGL) + return "New ordinary\ntransaction"; +#endif // HAVE_BAGL + + case SIGN_TX_SIGNINGMODE_POOL_REGISTRATION_OWNER: +#ifdef HAVE_BAGL + return "New pool owner"; +#elif defined(HAVE_NBGL) + return "New pool owner\ntransaction"; +#endif // HAVE_BAGL + + case SIGN_TX_SIGNINGMODE_POOL_REGISTRATION_OPERATOR: +#ifdef HAVE_BAGL + return "New pool operator"; +#elif defined(HAVE_NBGL) + return "New pool operator\ntransaction"; +#endif // HAVE_BAGL + + case SIGN_TX_SIGNINGMODE_MULTISIG_TX: +#ifdef HAVE_BAGL + return "New multisig"; +#elif defined(HAVE_NBGL) + return "New multisig\ntransaction"; +#endif // HAVE_BAGL + + case SIGN_TX_SIGNINGMODE_PLUTUS_TX: +#ifdef HAVE_BAGL + return "New Plutus"; +#elif defined(HAVE_NBGL) + return "New Plutus\ntransaction"; +#endif // HAVE_BAGL + + default: + ASSERT(false); + } +} + +#ifdef HAVE_NBGL +static void signTx_handleInit_ui_runStep_cb(void) { + char networkParams[100] = {0}; + ui_getNetworkParamsScreen_2( + networkParams, + SIZEOF(networkParams), + ctx->commonTxData.protocolMagic); + fill_and_display_if_required("Protocol magic", networkParams, signTx_handleInit_ui_runStep, respond_with_user_reject); +} +#endif // HAVE_NBGL + +void signTx_handleInit_ui_runStep() +{ + TRACE("UI step %d", ctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = signTx_handleInit_ui_runStep; + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + + UI_STEP(HANDLE_INIT_STEP_PROMPT_SIGNINGMODE) { +#ifdef HAVE_BAGL + ui_displayPrompt( + _newTxLine1(ctx->commonTxData.txSigningMode), + "transaction?", + this_fn, + respond_with_user_reject + ); +#elif defined(HAVE_NBGL) + display_prompt(_newTxLine1(ctx->commonTxData.txSigningMode), "", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + + UI_STEP(HANDLE_INIT_STEP_DISPLAY_NETWORK_DETAILS) { + const bool isNetworkIdVerifiable = isTxNetworkIdVerifiable( + ctx->includeNetworkId, + ctx->numOutputs, ctx->numWithdrawals, + ctx->commonTxData.txSigningMode + ); + if (isNetworkIdVerifiable) { + if (isNetworkUsual(ctx->commonTxData.networkId, ctx->commonTxData.protocolMagic)) { + // no need to display the network details + UI_STEP_JUMP(HANDLE_INIT_STEP_SCRIPT_RUNNING_WARNING); + } +#ifdef HAVE_BAGL + ui_displayNetworkParamsScreen( + "Network details", + ctx->commonTxData.networkId, ctx->commonTxData.protocolMagic, + this_fn + ); +#elif defined(HAVE_NBGL) + char networkParams[100] = {0}; + ui_getNetworkParamsScreen_1( + networkParams, + SIZEOF(networkParams), + ctx->commonTxData.networkId); + fill_and_display_if_required("Network ID", networkParams, signTx_handleInit_ui_runStep_cb, respond_with_user_reject); +#endif // HAVE_BAGL + } else { + // technically, no pool reg. certificate as well, but the UI message would be too long +#ifdef HAVE_BAGL + ui_displayPaginatedText( + "Warning:", + "cannot verify network id: no outputs or withdrawals", + this_fn + ); +#elif defined(HAVE_NBGL) + display_warning("Cannot verify network id:\nno outputs, or withdrawals", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + } + + UI_STEP(HANDLE_INIT_STEP_SCRIPT_RUNNING_WARNING) { + if (!needsRunningScriptWarning(ctx->numCollateralInputs)) { + UI_STEP_JUMP(HANDLE_INIT_STEP_NO_COLLATERAL_WARNING); + } +#ifdef HAVE_BAGL + ui_displayPaginatedText("WARNING:", "Plutus script will be evaluated", this_fn); +#elif defined(HAVE_NBGL) + display_warning("Plutus script will be evaluated", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + + UI_STEP(HANDLE_INIT_STEP_NO_COLLATERAL_WARNING) { + if (!needsMissingCollateralWarning(ctx->commonTxData.txSigningMode, ctx->numCollateralInputs)) { + UI_STEP_JUMP(HANDLE_INIT_STEP_NO_SCRIPT_DATA_HASH_WARNING); + } +#ifdef HAVE_BAGL + ui_displayPaginatedText("WARNING:", "No collateral given for Plutus transaction", this_fn); +#elif defined(HAVE_NBGL) + display_warning("No collateral given for\nPlutus transaction", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + + UI_STEP(HANDLE_INIT_STEP_UNKNOWN_COLLATERAL_WARNING) { + if (!needsUnknownCollateralWarning(ctx->commonTxData.txSigningMode, ctx->includeTotalCollateral)) { + UI_STEP_JUMP(HANDLE_INIT_STEP_NO_SCRIPT_DATA_HASH_WARNING); + } +#ifdef HAVE_BAGL + ui_displayPaginatedText("WARNING:", "Unknown collateral amount", this_fn); +#elif defined(HAVE_NBGL) + display_warning("Unknown collateral amount", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + + UI_STEP(HANDLE_INIT_STEP_NO_SCRIPT_DATA_HASH_WARNING) { + if (!needsMissingScriptDataHashWarning(ctx->commonTxData.txSigningMode, ctx->includeScriptDataHash)) { + UI_STEP_JUMP(HANDLE_INIT_STEP_RESPOND); + } +#ifdef HAVE_BAGL + ui_displayPaginatedText("WARNING:", "No script data given for Plutus transaction", this_fn); +#elif defined(HAVE_NBGL) + display_warning("No script data given for\nPlutus transaction", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + + UI_STEP(HANDLE_INIT_STEP_RESPOND) { + respondSuccessEmptyMsg(); + tx_advanceStage(); + } + UI_STEP_END(HANDLE_INIT_STEP_INVALID); +} + +// ============================== AUXILIARY DATA ============================== + +void signTx_handleAuxDataArbitraryHash_ui_runStep() +{ + TRACE("UI step %d", ctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = signTx_handleAuxDataArbitraryHash_ui_runStep; + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + + UI_STEP(HANDLE_AUX_DATA_ARBITRARY_HASH_STEP_DISPLAY) { +#ifdef HAVE_BAGL + ui_displayHexBufferScreen( + "Auxiliary data hash", + ctx->auxDataHash, + SIZEOF(ctx->auxDataHash), + this_fn + ); +#elif defined(HAVE_NBGL) + char bufferHex[2 * 32 + 1] = {0}; + ui_getHexBufferScreen(bufferHex, SIZEOF(bufferHex), ctx->auxDataHash, SIZEOF(ctx->auxDataHash)); + fill_and_display_if_required("Auxiliary data hash", bufferHex, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_AUX_DATA_ARBITRARY_HASH_STEP_RESPOND) { + respondSuccessEmptyMsg(); + tx_advanceStage(); + } + UI_STEP_END(HANDLE_AUX_DATA_ARBITRARY_HASH_STEP_INVALID); +} + +void signTx_handleAuxDataCVoteRegistration_ui_runStep() +{ + TRACE("UI step %d", ctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = signTx_handleAuxDataCVoteRegistration_ui_runStep; + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + + UI_STEP(HANDLE_AUX_DATA_CVOTE_REGISTRATION_STEP_DISPLAY) { +#ifdef HAVE_BAGL + ui_displayPrompt( + "Register vote", + "key (CIP-36)?", + this_fn, + respond_with_user_reject + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt("Register vote\nkey (CIP-36)?", "", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_AUX_DATA_CVOTE_REGISTRATION_STEP_RESPOND) { + respondSuccessEmptyMsg(); + signTxCVoteRegistration_init(); + ctx->stage = SIGN_STAGE_AUX_DATA_CVOTE_REGISTRATION_SUBMACHINE; + } + UI_STEP_END(HANDLE_AUX_DATA_CVOTE_REGISTRATION_STEP_INVALID); +} + +// ============================== INPUTS ============================== + +void signTx_handleInput_ui_runStep() +{ + TRACE("UI step %d", ctx->ui_step); + ui_callback_fn_t* this_fn = signTx_handleInput_ui_runStep; + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + + UI_STEP(HANDLE_INPUT_STEP_DISPLAY) { +#ifdef HAVE_BAGL + ui_displayInputScreen(&BODY_CTX->stageData.input, this_fn); +#elif defined(HAVE_NBGL) + // index 32 bit (10) + separator (" / ") + utxo hash hex format + \0 + // + 1 byte to detect if everything has been written + char inputStr[10 + 3 + TX_HASH_LENGTH * 2 + 1 + 1] = {0}; + + ui_getInputScreen(inputStr, SIZEOF(inputStr), &BODY_CTX->stageData.input); + fill_and_display_if_required(BODY_CTX->stageData.input.label, inputStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + + UI_STEP(HANDLE_INPUT_STEP_RESPOND) { + respondSuccessEmptyMsg(); + + ASSERT(ctx->ui_advanceState != NULL); + ctx->ui_advanceState(); + } + UI_STEP_END(HANDLE_INPUT_STEP_INVALID); +} + +// ============================== FEE ============================== + +void signTx_handleFee_ui_runStep() +{ + TRACE("UI step %d", ctx->ui_step); + ui_callback_fn_t* this_fn = signTx_handleFee_ui_runStep; + + TRACE_ADA_AMOUNT("fee ", BODY_CTX->stageData.fee); + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + + UI_STEP(HANDLE_FEE_STEP_DISPLAY) { +#ifdef HAVE_BAGL + ui_displayAdaAmountScreen("Transaction fee", BODY_CTX->stageData.fee, this_fn); +#elif defined(HAVE_NBGL) + char adaAmountStr[50] = {0}; + ui_getAdaAmountScreen(adaAmountStr, SIZEOF(adaAmountStr), BODY_CTX->stageData.fee); + fill_and_display_if_required("Transaction fee", adaAmountStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_FEE_STEP_RESPOND) { + respondSuccessEmptyMsg(); + tx_advanceStage(); + } + UI_STEP_END(HANDLE_FEE_STEP_INVALID); +} + +// ============================== TTL ============================== + +void signTx_handleTtl_ui_runStep() +{ + TRACE("UI step %d", ctx->ui_step); + ui_callback_fn_t* this_fn = signTx_handleTtl_ui_runStep; + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + + UI_STEP(HANDLE_TTL_STEP_DISPLAY) { +#ifdef HAVE_BAGL + ui_displayValidityBoundaryScreen( + "Transaction TTL", + BODY_CTX->stageData.ttl, + ctx->commonTxData.networkId, ctx->commonTxData.protocolMagic, + this_fn + ); +#elif defined(HAVE_NBGL) + char boundaryStr[30] = {0}; + ui_getValidityBoundaryScreen(boundaryStr, SIZEOF(boundaryStr), BODY_CTX->stageData.ttl, ctx->commonTxData.networkId, ctx->commonTxData.protocolMagic); + fill_and_display_if_required("Transaction TTL", boundaryStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_TTL_STEP_RESPOND) { + respondSuccessEmptyMsg(); + tx_advanceStage(); + } + UI_STEP_END(HANDLE_TTL_STEP_INVALID); +} + +// ============================== CERTIFICATES ============================== + +// called from main state machine when a pool registration certificate +// sub-machine is finished, or when other type of certificate is processed +static inline void advanceCertificatesStateIfAppropriate() +{ + TRACE("%u", ctx->stage); + + switch (ctx->stage) { + + case SIGN_STAGE_BODY_CERTIFICATES: { + ASSERT(BODY_CTX->currentCertificate < ctx->numCertificates); + + // Advance stage to the next certificate + ASSERT(BODY_CTX->currentCertificate < ctx->numCertificates); + BODY_CTX->currentCertificate++; + + if (BODY_CTX->currentCertificate == ctx->numCertificates) { + tx_advanceStage(); + } + } + break; + + default: + ASSERT(ctx->stage == SIGN_STAGE_BODY_CERTIFICATES_POOL_SUBMACHINE); + } +} + +#ifdef HAVE_NBGL +static void signTx_handleCertificate_ui_delegation_cb(void) { + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "pool", BODY_CTX->stageData.certificate.poolKeyHash, SIZEOF(BODY_CTX->stageData.certificate.poolKeyHash)); + fill_and_display_if_required("Pool", encodedStr, signTx_handleCertificate_ui_runStep, respond_with_user_reject); +} +#endif + +void signTx_handleCertificate_ui_runStep() +{ + TRACE("UI step %d", ctx->ui_step); + ui_callback_fn_t* this_fn = signTx_handleCertificate_ui_runStep; + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + + UI_STEP(HANDLE_CERTIFICATE_STEP_DISPLAY_OPERATION) { + switch (BODY_CTX->stageData.certificate.type) { + case CERTIFICATE_TYPE_STAKE_REGISTRATION: +#ifdef HAVE_BAGL + ui_displayPaginatedText( + "Register", + "staking key", + this_fn + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt("Register\nstaking key", "", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + break; + + case CERTIFICATE_TYPE_STAKE_DEREGISTRATION: +#ifdef HAVE_BAGL + ui_displayPaginatedText( + "Deregister", + "staking key", + this_fn + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt("Deregister\nstaking key", "", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + break; + + case CERTIFICATE_TYPE_STAKE_DELEGATION: +#ifdef HAVE_BAGL + ui_displayBech32Screen( + "Delegate stake to", + "pool", + BODY_CTX->stageData.certificate.poolKeyHash, SIZEOF(BODY_CTX->stageData.certificate.poolKeyHash), + this_fn + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt("Delegate staking\nconfirmation key", "", signTx_handleCertificate_ui_delegation_cb, respond_with_user_reject); +#endif // HAVE_BAGL + break; + + default: + // includes CERTIFICATE_TYPE_STAKE_POOL_REGISTRATION + // and CERTIFICATE_TYPE_STAKE_POOL_RETIREMENT + // which have separate UI; this handler must not be used + ASSERT(false); + } + } + UI_STEP(HANDLE_CERTIFICATE_STEP_DISPLAY_STAKING_KEY) { + switch (BODY_CTX->stageData.certificate.stakeCredential.type) { + case STAKE_CREDENTIAL_KEY_PATH: +#ifdef HAVE_BAGL + ui_displayPathScreen( + "Staking key", + &BODY_CTX->stageData.certificate.stakeCredential.keyPath, + this_fn + ); +#elif defined(HAVE_NBGL) + { + char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; + ui_getPathScreen(pathStr, SIZEOF(pathStr), &BODY_CTX->stageData.certificate.stakeCredential.keyPath); + fill_and_display_if_required("Staking key", pathStr, this_fn, respond_with_user_reject); + } +#endif // HAVE_BAGL + break; + case STAKE_CREDENTIAL_KEY_HASH: +#ifdef HAVE_BAGL + ui_displayBech32Screen( + "Staking key hash", + "stake_vkh", + BODY_CTX->stageData.certificate.stakeCredential.keyHash, + SIZEOF(BODY_CTX->stageData.certificate.stakeCredential.keyHash), + this_fn + ); +#elif defined(HAVE_NBGL) + { + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "stake_vkh", BODY_CTX->stageData.certificate.stakeCredential.keyHash, SIZEOF(BODY_CTX->stageData.certificate.stakeCredential.keyHash)); + fill_and_display_if_required("Staking key hash", encodedStr, this_fn, respond_with_user_reject); + } +#endif // HAVE_BAGL + break; + case STAKE_CREDENTIAL_SCRIPT_HASH: +#ifdef HAVE_BAGL + ui_displayBech32Screen( + "Staking script hash", + "script", + BODY_CTX->stageData.certificate.stakeCredential.scriptHash, + SIZEOF(BODY_CTX->stageData.certificate.stakeCredential.scriptHash), + this_fn + ); +#elif defined(HAVE_NBGL) + { + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "script", BODY_CTX->stageData.certificate.stakeCredential.scriptHash, SIZEOF(BODY_CTX->stageData.certificate.stakeCredential.scriptHash)); + fill_and_display_if_required("Staking script hash", encodedStr, this_fn, respond_with_user_reject); + } +#endif // HAVE_BAGL + break; + default: + ASSERT(false); + break; + } + } + UI_STEP(HANDLE_CERTIFICATE_STEP_CONFIRM) { + char description[50] = {0}; + explicit_bzero(description, SIZEOF(description)); + + switch (BODY_CTX->stageData.certificate.type) { + case CERTIFICATE_TYPE_STAKE_REGISTRATION: +#ifdef HAVE_BAGL + snprintf(description, SIZEOF(description), "registration?"); +#elif defined(HAVE_NBGL) + display_confirmation("Confirm\nregistration", "", "REGISTRATION\nACCEPTED", "Registration\nrejected", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + break; + + case CERTIFICATE_TYPE_STAKE_DEREGISTRATION: +#ifdef HAVE_BAGL + snprintf(description, SIZEOF(description), "deregistration?"); +#elif defined(HAVE_NBGL) + display_confirmation("Confirm\nderegistration", "", "DEREGISTRATION\nACCEPTED", "Deregistration\nrejected", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + break; + + case CERTIFICATE_TYPE_STAKE_DELEGATION: +#ifdef HAVE_BAGL + snprintf(description, SIZEOF(description), "delegation?"); +#elif defined(HAVE_NBGL) + display_confirmation("Confirm\ndelegation", "", "DELEGATION\nACCEPTED", "Delegation\nrejected", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + break; + + default: + ASSERT(false); + } + // make sure all the information is displayed to the user + ASSERT(strlen(description) + 1 < SIZEOF(description)); + +#ifdef HAVE_BAGL + ui_displayPrompt( + "Confirm", + description, + this_fn, + respond_with_user_reject + ); +#elif defined(HAVE_NBGL) +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_CERTIFICATE_STEP_RESPOND) { + respondSuccessEmptyMsg(); + + advanceCertificatesStateIfAppropriate(); + } + UI_STEP_END(HANDLE_CERTIFICATE_STEP_INVALID); +} + +void signTx_handleCertificatePoolRetirement_ui_runStep() +{ + TRACE("UI step %d", ctx->ui_step); + ASSERT(BODY_CTX->stageData.certificate.type == CERTIFICATE_TYPE_STAKE_POOL_RETIREMENT); + + ui_callback_fn_t* this_fn = signTx_handleCertificatePoolRetirement_ui_runStep; + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + + UI_STEP(HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_DISPLAY_OPERATION) { +#ifdef HAVE_BAGL + ui_displayBech32Screen( + "Retire stake pool", + "pool", + BODY_CTX->stageData.certificate.poolKeyHash, SIZEOF(BODY_CTX->stageData.certificate.poolKeyHash), + this_fn + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "pool", BODY_CTX->stageData.certificate.poolKeyHash, SIZEOF(BODY_CTX->stageData.certificate.poolKeyHash)); + fill_and_display_if_required("Retire stake pool", encodedStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_DISPLAY_EPOCH) { +#ifdef HAVE_BAGL + ui_displayUint64Screen( + "at the start of epoch", + BODY_CTX->stageData.certificate.epoch, + this_fn + ); +#elif defined(HAVE_NBGL) + char line[30]; + ui_getUint64Screen( + line, + SIZEOF(line), + BODY_CTX->stageData.certificate.epoch + ); + fill_and_display_if_required("Start of epoch", line, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_CONFIRM) { +#ifdef HAVE_BAGL + ui_displayPrompt( + "Confirm", + "pool retirement", + this_fn, + respond_with_user_reject + ); +#elif defined(HAVE_NBGL) + display_confirmation("Confirm\npool retirement", "", "POOL RETIREMENT\nCONFIRMED", "Pool retirement\nrejected", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_RESPOND) { + respondSuccessEmptyMsg(); + + advanceCertificatesStateIfAppropriate(); + } + UI_STEP_END(HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_INVALID); +} + +// ============================== WITHDRAWALS ============================== + +void signTx_handleWithdrawal_ui_runStep() +{ + TRACE("UI step %d", ctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = signTx_handleWithdrawal_ui_runStep; + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + + UI_STEP(HANDLE_WITHDRAWAL_STEP_DISPLAY_AMOUNT) { +#ifdef HAVE_BAGL + ui_displayAdaAmountScreen("Withdrawing rewards", BODY_CTX->stageData.withdrawal.amount, this_fn); +#elif defined(HAVE_NBGL) + char adaAmountStr[50] = {0}; + ui_getAdaAmountScreen(adaAmountStr, SIZEOF(adaAmountStr), BODY_CTX->stageData.withdrawal.amount); + fill_and_display_if_required("Withdrawing rewards", adaAmountStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_WITHDRAWAL_STEP_DISPLAY_PATH) { + reward_account_t rewardAccount; + switch (BODY_CTX->stageData.withdrawal.stakeCredential.type) { + case STAKE_CREDENTIAL_KEY_PATH: { + rewardAccount.keyReferenceType = KEY_REFERENCE_PATH; + rewardAccount.path = BODY_CTX->stageData.withdrawal.stakeCredential.keyPath; + break; + } + case STAKE_CREDENTIAL_KEY_HASH: { + rewardAccount.keyReferenceType = KEY_REFERENCE_HASH; + constructRewardAddressFromHash( + ctx->commonTxData.networkId, + REWARD_HASH_SOURCE_KEY, + BODY_CTX->stageData.withdrawal.stakeCredential.keyHash, + SIZEOF(BODY_CTX->stageData.withdrawal.stakeCredential.keyHash), + rewardAccount.hashBuffer, + SIZEOF(rewardAccount.hashBuffer) + ); + break; + } + case STAKE_CREDENTIAL_SCRIPT_HASH: { + rewardAccount.keyReferenceType = KEY_REFERENCE_HASH; + constructRewardAddressFromHash( + ctx->commonTxData.networkId, + REWARD_HASH_SOURCE_SCRIPT, + BODY_CTX->stageData.withdrawal.stakeCredential.scriptHash, + SIZEOF(BODY_CTX->stageData.withdrawal.stakeCredential.scriptHash), + rewardAccount.hashBuffer, + SIZEOF(rewardAccount.hashBuffer) + ); + break; + } + default: + ASSERT(false); + break; + } +#ifdef HAVE_BAGL + ui_displayRewardAccountScreen(&rewardAccount, ctx->commonTxData.networkId, this_fn); +#elif defined(HAVE_NBGL) + char firstLine[32] = {0}; + char secondLine[BIP44_PATH_STRING_SIZE_MAX + MAX_HUMAN_REWARD_ACCOUNT_SIZE + 2] = {0}; + ui_getRewardAccountScreen(firstLine, SIZEOF(firstLine), secondLine, SIZEOF(secondLine), &rewardAccount, ctx->commonTxData.networkId); + fill_and_display_if_required(firstLine, secondLine, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_WITHDRAWAL_STEP_RESPOND) { + respondSuccessEmptyMsg(); + + // Advance stage to the next withdrawal + ASSERT(BODY_CTX->currentWithdrawal < ctx->numWithdrawals); + BODY_CTX->currentWithdrawal++; + + if (BODY_CTX->currentWithdrawal == ctx->numWithdrawals) { + tx_advanceStage(); + } + } + UI_STEP_END(HANDLE_WITHDRAWAL_STEP_INVALID); +} + +// ============================== VALIDITY INTERVAL START ============================== + +void signTx_handleValidityInterval_ui_runStep() +{ + TRACE("UI step %d", ctx->ui_step); + ui_callback_fn_t* this_fn = signTx_handleValidityInterval_ui_runStep; + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + + UI_STEP(HANDLE_VALIDITY_INTERVAL_START_STEP_DISPLAY) { +#ifdef HAVE_BAGL + ui_displayValidityBoundaryScreen( + "Validity interval start", + BODY_CTX->stageData.validityIntervalStart, + ctx->commonTxData.networkId, ctx->commonTxData.protocolMagic, + this_fn + ); +#elif defined(HAVE_NBGL) + char boundaryStr[30] = {0}; + ui_getValidityBoundaryScreen(boundaryStr, SIZEOF(boundaryStr), BODY_CTX->stageData.validityIntervalStart, ctx->commonTxData.networkId, ctx->commonTxData.protocolMagic); + fill_and_display_if_required("Validity interval start", boundaryStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_VALIDITY_INTERVAL_START_STEP_RESPOND) { + respondSuccessEmptyMsg(); + tx_advanceStage(); + } + UI_STEP_END(HANDLE_VALIDITY_INTERVAL_START_STEP_INVALID); +} + +// ========================= SCRIPT DATA HASH ========================== + +void signTx_handleScriptDataHash_ui_runStep() +{ + TRACE("UI step %d", ctx->ui_step); + ui_callback_fn_t* this_fn = signTx_handleScriptDataHash_ui_runStep; + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + + UI_STEP(HANDLE_SCRIPT_DATA_HASH_STEP_DISPLAY) { +#ifdef HAVE_BAGL + ui_displayBech32Screen( + "Script data hash", + "script_data", + BODY_CTX->stageData.scriptDataHash, SCRIPT_DATA_HASH_LENGTH, + this_fn + ); +#elif defined(HAVE_NBGL) + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "script_data", BODY_CTX->stageData.scriptDataHash, SIZEOF(BODY_CTX->stageData.scriptDataHash)); + fill_and_display_if_required("Script data hash", encodedStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_SCRIPT_DATA_HASH_STEP_RESPOND) { + respondSuccessEmptyMsg(); + tx_advanceStage(); + } + UI_STEP_END(HANDLE_FEE_STEP_INVALID); +} + +// ========================= REQUIRED SIGNERS =========================== + +void signTx_handleRequiredSigner_ui_runStep() +{ + TRACE("UI step %d", ctx->ui_step); + ui_callback_fn_t* this_fn = signTx_handleRequiredSigner_ui_runStep; + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + + UI_STEP(HANDLE_REQUIRED_SIGNERS_STEP_DISPLAY) { + switch (BODY_CTX->stageData.requiredSigner.type) { + case REQUIRED_SIGNER_WITH_PATH: +#ifdef HAVE_BAGL + ui_displayPathScreen("Required signer", &BODY_CTX->stageData.requiredSigner.keyPath, this_fn); +#elif defined(HAVE_NBGL) + char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; + ui_getPathScreen(pathStr, SIZEOF(pathStr), &BODY_CTX->stageData.requiredSigner.keyPath); + fill_and_display_if_required("Required signer", pathStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + break; + case REQUIRED_SIGNER_WITH_HASH: +#ifdef HAVE_BAGL + ui_displayBech32Screen( + "Required signer", + "req_signer_vkh", + BODY_CTX->stageData.requiredSigner.keyHash, + SIZEOF(BODY_CTX->stageData.requiredSigner.keyHash), + this_fn + ); +#elif defined(HAVE_NBGL) + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "req_signer_vfk", BODY_CTX->stageData.requiredSigner.keyHash, SIZEOF(BODY_CTX->stageData.requiredSigner.keyHash)); + fill_and_display_if_required("Required signer", encodedStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + break; + + default: + ASSERT(false); + break; + } + } + + UI_STEP(HANDLE_REQUIRED_SIGNERS_STEP_RESPOND) { + respondSuccessEmptyMsg(); + + // Advance stage to the next input + ASSERT(BODY_CTX->currentRequiredSigner < ctx->numRequiredSigners); + BODY_CTX->currentRequiredSigner++; + + if (BODY_CTX->currentRequiredSigner == ctx->numRequiredSigners) { + tx_advanceStage(); + } + } + UI_STEP_END(HANDLE_REQUIRED_SIGNERS_STEP_INVALID); +} + +// ========================= TOTAL COLLATERAL =========================== + +void signTx_handleTotalCollateral_ui_runStep() +{ + TRACE("UI step %d", ctx->ui_step); + ui_callback_fn_t* this_fn = signTx_handleTotalCollateral_ui_runStep; + + TRACE_ADA_AMOUNT("total collateral ", BODY_CTX->stageData.totalCollateral); + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + + UI_STEP(HANDLE_TOTAL_COLLATERAL_STEP_DISPLAY) { +#ifdef HAVE_BAGL + ui_displayAdaAmountScreen("Total collateral", BODY_CTX->stageData.totalCollateral, this_fn); +#elif defined(HAVE_NBGL) + char adaAmountStr[50] = {0}; + ui_getAdaAmountScreen(adaAmountStr, SIZEOF(adaAmountStr), BODY_CTX->stageData.totalCollateral); + fill_and_display_if_required("Total collateral", adaAmountStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_TOTAL_COLLATERAL_STEP_RESPOND) { + respondSuccessEmptyMsg(); + tx_advanceStage(); + } + UI_STEP_END(HANDLE_TOTAL_COLLATERAL_STEP_INVALID); +} + +// ============================== CONFIRM ============================== + +void signTx_handleConfirm_ui_runStep() +{ + TRACE("UI step %d", ctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = signTx_handleConfirm_ui_runStep; + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + + UI_STEP(HANDLE_CONFIRM_STEP_TXID) { +#ifdef HAVE_BAGL + ui_displayHexBufferScreen( + "Transaction id", + ctx->txHash, SIZEOF(ctx->txHash), + this_fn + ); +#elif defined(HAVE_NBGL) + char bufferHex[2 * 32 + 1] = {0}; + ui_getHexBufferScreen(bufferHex, SIZEOF(bufferHex), ctx->txHash, SIZEOF(ctx->txHash)); + fill_and_display_if_required("Transaction id", bufferHex, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM) { +#ifdef HAVE_BAGL + ui_displayPrompt( + "Confirm", + "transaction?", + this_fn, + respond_with_user_reject + ); +#elif defined(HAVE_NBGL) + display_confirmation("Sign\ntransaction", "", "TRANSACTION\nSIGNED", "Transaction\nrejected", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { + io_send_buf(SUCCESS, ctx->txHash, SIZEOF(ctx->txHash)); +#ifdef HAVE_BAGL + ui_displayBusy(); // displays dots, called only after I/O to avoid freezing +#endif // HAVE_BAGL + + tx_advanceStage(); + } + UI_STEP_END(HANDLE_CONFIRM_STEP_INVALID); +} + +// ============================== WITNESS ============================== + +static void _wipeWitnessSignature() +{ + // safer not to keep the signature in memory + explicit_bzero(WITNESS_CTX->stageData.witness.signature, SIZEOF(WITNESS_CTX->stageData.witness.signature)); + respond_with_user_reject(); +} + +void signTx_handleWitness_ui_runStep() +{ + TRACE("UI step %d", ctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = signTx_handleWitness_ui_runStep; + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + + UI_STEP(HANDLE_WITNESS_STEP_WARNING) { +#ifdef HAVE_BAGL + ui_displayPaginatedText( + "WARNING:", + "unusual witness requested", + this_fn + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning("Unusual\nwitness requested", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_WITNESS_STEP_DISPLAY) { +#ifdef HAVE_BAGL + ui_displayPathScreen("Witness path", &WITNESS_CTX->stageData.witness.path, this_fn); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; + ui_getPathScreen(pathStr, SIZEOF(pathStr), &WITNESS_CTX->stageData.witness.path); + fill_and_display_if_required("Witness path", pathStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_WITNESS_STEP_CONFIRM) { +#ifdef HAVE_BAGL + ui_displayPrompt( + "Sign using", + "this witness?", + this_fn, + _wipeWitnessSignature + ); +#elif defined(HAVE_NBGL) + display_confirmation("Sign using witness", "", "SIGNATURE\nCONFIRMED", "Signature\nrejected", this_fn, _wipeWitnessSignature); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_WITNESS_STEP_RESPOND) { + TRACE("Sending witness data"); + TRACE_BUFFER(WITNESS_CTX->stageData.witness.signature, SIZEOF(WITNESS_CTX->stageData.witness.signature)); + io_send_buf(SUCCESS, WITNESS_CTX->stageData.witness.signature, SIZEOF(WITNESS_CTX->stageData.witness.signature)); +#ifdef HAVE_BAGL + ui_displayBusy(); // displays dots, called only after I/O to avoid freezing +#endif // HAVE_BAGL + + WITNESS_CTX->currentWitness++; + if (WITNESS_CTX->currentWitness == ctx->numWitnesses) { + tx_advanceStage(); + } + } + UI_STEP_END(HANDLE_WITNESS_STEP_INVALID); +} diff --git a/src/signTx_ui.h b/src/signTx_ui.h new file mode 100644 index 00000000..11982f34 --- /dev/null +++ b/src/signTx_ui.h @@ -0,0 +1,163 @@ +#ifndef H_CARDANO_APP_SIGN_TX_UI +#define H_CARDANO_APP_SIGN_TX_UI + +// ============================== INIT ============================== + +enum { + HANDLE_INIT_STEP_PROMPT_SIGNINGMODE = 100, + HANDLE_INIT_STEP_DISPLAY_NETWORK_DETAILS, + HANDLE_INIT_STEP_SCRIPT_RUNNING_WARNING, + HANDLE_INIT_STEP_NO_COLLATERAL_WARNING, + HANDLE_INIT_STEP_UNKNOWN_COLLATERAL_WARNING, + HANDLE_INIT_STEP_NO_SCRIPT_DATA_HASH_WARNING, + HANDLE_INIT_STEP_RESPOND, + HANDLE_INIT_STEP_INVALID, +} ; + +void signTx_handleInit_ui_runStep(); + +// ============================== AUXILIARY DATA ============================== + +enum { + HANDLE_AUX_DATA_ARBITRARY_HASH_STEP_DISPLAY = 800, + HANDLE_AUX_DATA_ARBITRARY_HASH_STEP_RESPOND, + HANDLE_AUX_DATA_ARBITRARY_HASH_STEP_INVALID, +}; + +void signTx_handleAuxDataArbitraryHash_ui_runStep(); + +enum { + HANDLE_AUX_DATA_CVOTE_REGISTRATION_STEP_DISPLAY = 850, + HANDLE_AUX_DATA_CVOTE_REGISTRATION_STEP_RESPOND, + HANDLE_AUX_DATA_CVOTE_REGISTRATION_STEP_INVALID, +}; + +void signTx_handleAuxDataCVoteRegistration_ui_runStep(); + +// ============================== INPUTS ============================== + +enum { + HANDLE_INPUT_STEP_DISPLAY = 200, + HANDLE_INPUT_STEP_RESPOND, + HANDLE_INPUT_STEP_INVALID, +}; + +void signTx_handleInput_ui_runStep(); + +// ============================== FEE ============================== + +enum { + HANDLE_FEE_STEP_DISPLAY = 400, + HANDLE_FEE_STEP_RESPOND, + HANDLE_FEE_STEP_INVALID, +}; + +void signTx_handleFee_ui_runStep(); + +// ============================== TTL ============================== + +enum { + HANDLE_TTL_STEP_DISPLAY = 500, + HANDLE_TTL_STEP_RESPOND, + HANDLE_TTL_STEP_INVALID, +}; + +void signTx_handleTtl_ui_runStep(); + +// ============================== CERTIFICATES ============================== + +enum { + HANDLE_CERTIFICATE_STEP_DISPLAY_OPERATION = 600, + HANDLE_CERTIFICATE_STEP_DISPLAY_STAKING_KEY, + HANDLE_CERTIFICATE_STEP_CONFIRM, + HANDLE_CERTIFICATE_STEP_RESPOND, + HANDLE_CERTIFICATE_STEP_INVALID, +}; + +void signTx_handleCertificate_ui_runStep(); + +enum { + HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_DISPLAY_OPERATION = 650, + HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_DISPLAY_EPOCH, + HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_CONFIRM, + HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_RESPOND, + HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_INVALID, +}; + +void signTx_handleCertificatePoolRetirement_ui_runStep(); + +// ============================== WITHDRAWALS ============================== + +enum { + HANDLE_WITHDRAWAL_STEP_DISPLAY_AMOUNT = 700, + HANDLE_WITHDRAWAL_STEP_DISPLAY_PATH, + HANDLE_WITHDRAWAL_STEP_RESPOND, + HANDLE_WITHDRAWAL_STEP_INVALID, +}; + +void signTx_handleWithdrawal_ui_runStep(); + +// ============================== VALIDITY INTERVAL START ============================== + +enum { + HANDLE_VALIDITY_INTERVAL_START_STEP_DISPLAY = 900, + HANDLE_VALIDITY_INTERVAL_START_STEP_RESPOND, + HANDLE_VALIDITY_INTERVAL_START_STEP_INVALID, +}; + +void signTx_handleValidityInterval_ui_runStep(); + +// ========================= SCRIPT DATA HASH ========================== + + +enum { + HANDLE_SCRIPT_DATA_HASH_STEP_DISPLAY = 1200, + HANDLE_SCRIPT_DATA_HASH_STEP_RESPOND, + HANDLE_SCRIPT_DATA_HASH_STEP_INVALID, +}; + +void signTx_handleScriptDataHash_ui_runStep(); + +// ========================= REQUIRED SIGNERS =========================== + +enum { + HANDLE_REQUIRED_SIGNERS_STEP_DISPLAY = 1400, + HANDLE_REQUIRED_SIGNERS_STEP_RESPOND, + HANDLE_REQUIRED_SIGNERS_STEP_INVALID, +}; + +void signTx_handleRequiredSigner_ui_runStep(); + +// ========================= TOTAL COLLATERAL =========================== + +enum { + HANDLE_TOTAL_COLLATERAL_STEP_DISPLAY = 400, + HANDLE_TOTAL_COLLATERAL_STEP_RESPOND, + HANDLE_TOTAL_COLLATERAL_STEP_INVALID, +}; + +void signTx_handleTotalCollateral_ui_runStep(); + +// ============================== CONFIRM ============================== + +enum { + HANDLE_CONFIRM_STEP_TXID = 1000, + HANDLE_CONFIRM_STEP_FINAL_CONFIRM, + HANDLE_CONFIRM_STEP_RESPOND, + HANDLE_CONFIRM_STEP_INVALID, +}; + +void signTx_handleConfirm_ui_runStep(); + +// ============================== WITNESS ============================== + +enum { + HANDLE_WITNESS_STEP_WARNING = 1100, + HANDLE_WITNESS_STEP_DISPLAY, + HANDLE_WITNESS_STEP_CONFIRM, + HANDLE_WITNESS_STEP_RESPOND, + HANDLE_WITNESS_STEP_INVALID, +}; + +void signTx_handleWitness_ui_runStep(); +#endif // H_CARDANO_APP_SIGN_TX_UI From d21793e220be401bc9b2076dbc01af8d104f16e2 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 18 Oct 2022 19:58:35 +0200 Subject: [PATCH 014/105] signTxMint: update for stax --- src/signTxMint.c | 188 ++-------------------------------------- src/signTxMint_ui.c | 205 ++++++++++++++++++++++++++++++++++++++++++++ src/signTxMint_ui.h | 37 ++++++++ 3 files changed, 249 insertions(+), 181 deletions(-) create mode 100644 src/signTxMint_ui.c create mode 100644 src/signTxMint_ui.h diff --git a/src/signTxMint.c b/src/signTxMint.c index cbd3b325..589b499b 100644 --- a/src/signTxMint.c +++ b/src/signTxMint.c @@ -1,13 +1,19 @@ #include "signTxMint.h" +#include "signTxMint_ui.h" #include "signTxUtils.h" #include "state.h" #include "uiHelpers.h" #include "utils.h" -#include "uiScreens.h" #include "textUtils.h" #include "securityPolicy.h" #include "tokens.h" +#ifdef HAVE_BAGL +#include "uiScreens_bagl.h" +#elif defined(HAVE_NBGL) +#include "uiScreens_nbgl.h" +#endif + static common_tx_data_t* commonTxData = &(instructionState.signTxContext.commonTxData); static mint_context_t* accessSubcontext() @@ -22,91 +28,6 @@ static inline void CHECK_STATE(sign_tx_mint_state_t expected) VALIDATE(subctx->state == expected, ERR_INVALID_STATE); } -static inline void advanceState() -{ - mint_context_t* subctx = accessSubcontext(); - TRACE("Advancing mint state from: %d", subctx->state); - - switch (subctx->state) { - - case STATE_MINT_TOP_LEVEL_DATA: - ASSERT(subctx->numAssetGroups > 0); - ASSERT(subctx->currentAssetGroup == 0); - subctx->state = STATE_MINT_ASSET_GROUP; - break; - - case STATE_MINT_ASSET_GROUP: - ASSERT(subctx->currentAssetGroup < subctx->numAssetGroups); - - // we are going to receive token amounts for this group - ASSERT(subctx->numTokens > 0); - ASSERT(subctx->currentToken == 0); - - subctx->state = STATE_MINT_TOKEN; - break; - - case STATE_MINT_TOKEN: - // we are done with the current token group - ASSERT(subctx->currentToken == subctx->numTokens); - subctx->currentToken = 0; - ASSERT(subctx->currentAssetGroup < subctx->numAssetGroups); - subctx->currentAssetGroup++; - - if (subctx->currentAssetGroup == subctx->numAssetGroups) { - // the whole token bundle has been received - subctx->state = STATE_MINT_CONFIRM; - } else { - subctx->state = STATE_MINT_ASSET_GROUP; - } - break; - - case STATE_MINT_CONFIRM: - subctx->state = STATE_MINT_FINISHED; - break; - - default: - ASSERT(false); - } - - TRACE("Advancing mint state to: %d", subctx->state); -} - -enum { - HANDLE_MINT_TOP_LEVEL_DATA_DISPLAY = 9200, - HANDLE_MINT_TOP_LEVEL_DATA_RESPOND, - HANDLE_MINT_TOP_LEVEL_DATA_INVALID, -}; - -__noinline_due_to_stack__ -static void signTxMint_handleTopLevelData_ui_runStep() -{ - mint_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - - ui_callback_fn_t* this_fn = signTxMint_handleTopLevelData_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_MINT_TOP_LEVEL_DATA_DISPLAY) { - char secondLine[50] = {0}; - explicit_bzero(secondLine, SIZEOF(secondLine)); - STATIC_ASSERT(!IS_SIGNED(subctx->numAssetGroups), "signed type for %u"); - snprintf(secondLine, SIZEOF(secondLine), "%u asset groups", subctx->numAssetGroups); - ASSERT(strlen(secondLine) + 1 < SIZEOF(secondLine)); - - ui_displayPaginatedText( - "Mint", - secondLine, - this_fn - ); - } - UI_STEP(HANDLE_MINT_TOP_LEVEL_DATA_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_MINT_TOP_LEVEL_DATA_INVALID); -} - static void signTxMint_handleTopLevelDataAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) { { @@ -139,28 +60,6 @@ static void signTxMint_handleTopLevelDataAPDU(const uint8_t* wireDataBuffer, siz signTxMint_handleTopLevelData_ui_runStep(); } -enum { - HANDLE_ASSET_GROUP_STEP_DISPLAY = 9300, - HANDLE_ASSET_GROUP_STEP_RESPOND, - HANDLE_ASSET_GROUP_STEP_INVALID, -}; - -static void signTxMint_handleAssetGroup_ui_runStep() -{ - mint_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - - ui_callback_fn_t* this_fn = signTxMint_handleAssetGroup_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_ASSET_GROUP_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_ASSET_GROUP_STEP_INVALID); -} - static void signTxMint_handleAssetGroupAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) { { @@ -216,50 +115,6 @@ static void signTxMint_handleAssetGroupAPDU(const uint8_t* wireDataBuffer, size_ signTxMint_handleAssetGroup_ui_runStep(); } -enum { - HANDLE_TOKEN_STEP_DISPLAY_NAME = 9400, - HANDLE_TOKEN_STEP_DISPLAY_AMOUNT, - HANDLE_TOKEN_STEP_RESPOND, - HANDLE_TOKEN_STEP_INVALID, -}; - - -static void signTxMint_handleToken_ui_runStep() -{ - mint_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - ui_callback_fn_t* this_fn = signTxMint_handleToken_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_TOKEN_STEP_DISPLAY_NAME) { - ui_displayAssetFingerprintScreen( - &subctx->stateData.tokenGroup, - subctx->stateData.token.assetNameBytes, subctx->stateData.token.assetNameSize, - this_fn - ); - } - UI_STEP(HANDLE_TOKEN_STEP_DISPLAY_AMOUNT) { - ui_displayTokenAmountMintScreen( - &subctx->stateData.tokenGroup, - subctx->stateData.token.assetNameBytes, subctx->stateData.token.assetNameSize, - subctx->stateData.token.amount, - this_fn - ); - } - UI_STEP(HANDLE_TOKEN_STEP_RESPOND) { - respondSuccessEmptyMsg(); - - ASSERT(subctx->currentToken < subctx->numTokens); - subctx->currentToken++; - - if (subctx->currentToken == subctx->numTokens) { - advanceState(); - } - } - UI_STEP_END(HANDLE_TOKEN_STEP_INVALID); -} - static void signTxMint_handleTokenAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) { { @@ -325,35 +180,6 @@ static void signTxMint_handleTokenAPDU(const uint8_t* wireDataBuffer, size_t wir signTxMint_handleToken_ui_runStep(); } -enum { - HANDLE_CONFIRM_STEP_FINAL_CONFIRM = 9500, - HANDLE_CONFIRM_STEP_RESPOND, - HANDLE_CONFIRM_STEP_INVALID, -}; - -static void signTxMint_handleConfirm_ui_runStep() -{ - mint_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - ui_callback_fn_t* this_fn = signTxMint_handleConfirm_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM) { - ui_displayPrompt( - "Confirm", - "mint?", - this_fn, - respond_with_user_reject - ); - } - UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_CONFIRM_STEP_INVALID); -} - static void signTxMint_handleConfirmAPDU(const uint8_t* wireDataBuffer MARK_UNUSED, size_t wireDataSize) { { diff --git a/src/signTxMint_ui.c b/src/signTxMint_ui.c new file mode 100644 index 00000000..9b703849 --- /dev/null +++ b/src/signTxMint_ui.c @@ -0,0 +1,205 @@ +#include "signTxMint.h" +#include "signTxMint_ui.h" +#include "signTxUtils.h" +#include "state.h" +#include "uiHelpers.h" +#include "utils.h" +#include "textUtils.h" +#include "securityPolicy.h" +#include "tokens.h" + +#ifdef HAVE_BAGL +#include "uiScreens_bagl.h" +#elif defined(HAVE_NBGL) +#include "uiScreens_nbgl.h" +#endif + +static mint_context_t* accessSubcontext() +{ + return &BODY_CTX->stageContext.mint_subctx; +} + +static inline void advanceState() +{ + mint_context_t* subctx = accessSubcontext(); + TRACE("Advancing mint state from: %d", subctx->state); + + switch (subctx->state) { + + case STATE_MINT_TOP_LEVEL_DATA: + ASSERT(subctx->numAssetGroups > 0); + ASSERT(subctx->currentAssetGroup == 0); + subctx->state = STATE_MINT_ASSET_GROUP; + break; + + case STATE_MINT_ASSET_GROUP: + ASSERT(subctx->currentAssetGroup < subctx->numAssetGroups); + + // we are going to receive token amounts for this group + ASSERT(subctx->numTokens > 0); + ASSERT(subctx->currentToken == 0); + + subctx->state = STATE_MINT_TOKEN; + break; + + case STATE_MINT_TOKEN: + // we are done with the current token group + ASSERT(subctx->currentToken == subctx->numTokens); + subctx->currentToken = 0; + ASSERT(subctx->currentAssetGroup < subctx->numAssetGroups); + subctx->currentAssetGroup++; + + if (subctx->currentAssetGroup == subctx->numAssetGroups) { + // the whole token bundle has been received + subctx->state = STATE_MINT_CONFIRM; + } else { + subctx->state = STATE_MINT_ASSET_GROUP; + } + break; + + case STATE_MINT_CONFIRM: + subctx->state = STATE_MINT_FINISHED; + break; + + default: + ASSERT(false); + } + + TRACE("Advancing mint state to: %d", subctx->state); +} +__noinline_due_to_stack__ +void signTxMint_handleTopLevelData_ui_runStep() +{ + mint_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + + ui_callback_fn_t* this_fn = signTxMint_handleTopLevelData_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_MINT_TOP_LEVEL_DATA_DISPLAY) { + char secondLine[50] = {0}; + explicit_bzero(secondLine, SIZEOF(secondLine)); + STATIC_ASSERT(!IS_SIGNED(subctx->numAssetGroups), "signed type for %u"); + snprintf(secondLine, SIZEOF(secondLine), "%u asset groups", subctx->numAssetGroups); + ASSERT(strlen(secondLine) + 1 < SIZEOF(secondLine)); + +#ifdef HAVE_BAGL + ui_displayPaginatedText( + "Mint", + secondLine, + this_fn + ); +#elif defined(HAVE_NBGL) + display_prompt("Mint", secondLine, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_MINT_TOP_LEVEL_DATA_RESPOND) { + respondSuccessEmptyMsg(); + + advanceState(); + } + UI_STEP_END(HANDLE_MINT_TOP_LEVEL_DATA_INVALID); +} + +void signTxMint_handleAssetGroup_ui_runStep() +{ + mint_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + + ui_callback_fn_t* this_fn = signTxMint_handleAssetGroup_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_ASSET_GROUP_STEP_RESPOND) { + respondSuccessEmptyMsg(); + advanceState(); + } + UI_STEP_END(HANDLE_ASSET_GROUP_STEP_INVALID); +} + +void signTxMint_handleToken_ui_runStep() +{ + mint_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + ui_callback_fn_t* this_fn = signTxMint_handleToken_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_TOKEN_STEP_DISPLAY_NAME) { +#ifdef HAVE_BAGL + ui_displayAssetFingerprintScreen( + &subctx->stateData.tokenGroup, + subctx->stateData.token.assetNameBytes, subctx->stateData.token.assetNameSize, + this_fn + ); +#elif defined(HAVE_NBGL) + char fingerprint[200] = {0}; + ui_getAssetFingerprintScreen( + fingerprint, + SIZEOF(fingerprint), + &subctx->stateData.tokenGroup, + subctx->stateData.token.assetNameBytes, subctx->stateData.token.assetNameSize + ); + fill_and_display_if_required("Asset fingerprint", fingerprint, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_TOKEN_STEP_DISPLAY_AMOUNT) { +#ifdef HAVE_BAGL + ui_displayTokenAmountMintScreen( + &subctx->stateData.tokenGroup, + subctx->stateData.token.assetNameBytes, subctx->stateData.token.assetNameSize, + subctx->stateData.token.amount, + this_fn + ); +#elif defined(HAVE_NBGL) + char tokenAmountStr[70] = {0}; + ui_getTokenAmountMintScreen( + tokenAmountStr, + SIZEOF(tokenAmountStr), + &subctx->stateData.tokenGroup, + subctx->stateData.token.assetNameBytes, subctx->stateData.token.assetNameSize, + subctx->stateData.token.amount + ); + fill_and_display_if_required("Token amount", tokenAmountStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_TOKEN_STEP_RESPOND) { + respondSuccessEmptyMsg(); + + ASSERT(subctx->currentToken < subctx->numTokens); + subctx->currentToken++; + + if (subctx->currentToken == subctx->numTokens) { + advanceState(); + } + } + UI_STEP_END(HANDLE_TOKEN_STEP_INVALID); +} + +void signTxMint_handleConfirm_ui_runStep() +{ + mint_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + ui_callback_fn_t* this_fn = signTxMint_handleConfirm_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM) { +#ifdef HAVE_BAGL + ui_displayPrompt( + "Confirm", + "mint?", + this_fn, + respond_with_user_reject + ); +#elif defined(HAVE_NBGL) + display_confirmation("Confirm mint", "", "MINT\nCONFIRMED", "Mint\nrejected", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { + respondSuccessEmptyMsg(); + advanceState(); + } + UI_STEP_END(HANDLE_CONFIRM_STEP_INVALID); +} diff --git a/src/signTxMint_ui.h b/src/signTxMint_ui.h new file mode 100644 index 00000000..be87f434 --- /dev/null +++ b/src/signTxMint_ui.h @@ -0,0 +1,37 @@ +#ifndef H_CARDANO_APP_SIGN_TX_MINT_UI +#define H_CARDANO_APP_SIGN_TX_MINT_UI + +enum { + HANDLE_MINT_TOP_LEVEL_DATA_DISPLAY = 9200, + HANDLE_MINT_TOP_LEVEL_DATA_RESPOND, + HANDLE_MINT_TOP_LEVEL_DATA_INVALID, +}; + +void signTxMint_handleTopLevelData_ui_runStep(); + +enum { + HANDLE_ASSET_GROUP_STEP_DISPLAY = 9300, + HANDLE_ASSET_GROUP_STEP_RESPOND, + HANDLE_ASSET_GROUP_STEP_INVALID, +}; + +void signTxMint_handleAssetGroup_ui_runStep(); + +enum { + HANDLE_TOKEN_STEP_DISPLAY_NAME = 9400, + HANDLE_TOKEN_STEP_DISPLAY_AMOUNT, + HANDLE_TOKEN_STEP_RESPOND, + HANDLE_TOKEN_STEP_INVALID, +}; + +void signTxMint_handleToken_ui_runStep(); + +enum { + HANDLE_CONFIRM_STEP_FINAL_CONFIRM = 9500, + HANDLE_CONFIRM_STEP_RESPOND, + HANDLE_CONFIRM_STEP_INVALID, +}; + +void signTxMint_handleConfirm_ui_runStep(); + +#endif // H_CARDANO_APP_SIGN_TX_MINT_UI From c1faaaa62a5d32a51cbb01be4c5a7ce96eb99f8d Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 18 Oct 2022 20:05:07 +0200 Subject: [PATCH 015/105] signTxPoolRegistration: update for stax --- src/signTxPoolRegistration.c | 541 +--------------------- src/signTxPoolRegistration_ui.c | 793 ++++++++++++++++++++++++++++++++ src/signTxPoolRegistration_ui.h | 125 +++++ 3 files changed, 925 insertions(+), 534 deletions(-) create mode 100644 src/signTxPoolRegistration_ui.c create mode 100644 src/signTxPoolRegistration_ui.h diff --git a/src/signTxPoolRegistration.c b/src/signTxPoolRegistration.c index 78635b37..80fc4935 100644 --- a/src/signTxPoolRegistration.c +++ b/src/signTxPoolRegistration.c @@ -1,11 +1,11 @@ #include "signTx.h" +#include "signTxPoolRegistration_ui.h" #include "state.h" #include "cardano.h" #include "addressUtilsShelley.h" #include "keyDerivation.h" #include "uiHelpers.h" #include "signTxUtils.h" -#include "uiScreens.h" #include "txHashBuilder.h" #include "textUtils.h" #include "hexUtils.h" @@ -13,6 +13,12 @@ #include "securityPolicy.h" #include "signTxPoolRegistration.h" +#ifdef HAVE_BAGL +#include "uiScreens_bagl.h" +#elif defined(HAVE_NBGL) +#include "uiScreens_nbgl.h" +#endif + static ins_sign_tx_context_t* ctx = &(instructionState.signTxContext); static common_tx_data_t* commonTxData = &(instructionState.signTxContext.commonTxData); @@ -58,104 +64,8 @@ static inline void CHECK_STATE(sign_tx_pool_registration_state_t expected) VALIDATE(subctx->state == expected, ERR_INVALID_STATE); } -static inline void advanceState() -{ - pool_registration_context_t* subctx = accessSubcontext(); - TRACE("Advancing pool registration certificate state from: %d", subctx->state); - - switch (subctx->state) { - - case STAKE_POOL_REGISTRATION_INIT: - subctx->state = STAKE_POOL_REGISTRATION_POOL_KEY; - break; - - case STAKE_POOL_REGISTRATION_POOL_KEY: - subctx->state = STAKE_POOL_REGISTRATION_VRF_KEY; - break; - - case STAKE_POOL_REGISTRATION_VRF_KEY: - subctx->state = STAKE_POOL_REGISTRATION_FINANCIALS; - break; - - case STAKE_POOL_REGISTRATION_FINANCIALS: - subctx->state = STAKE_POOL_REGISTRATION_REWARD_ACCOUNT; - break; - - case STAKE_POOL_REGISTRATION_REWARD_ACCOUNT: - txHashBuilder_addPoolRegistrationCertificate_enterOwners(&BODY_CTX->txHashBuilder); - subctx->state = STAKE_POOL_REGISTRATION_OWNERS; - - if (subctx->numOwners > 0) { - break; - } - - // intentional fallthrough - - case STAKE_POOL_REGISTRATION_OWNERS: - ASSERT(subctx->currentOwner == subctx->numOwners); - - txHashBuilder_addPoolRegistrationCertificate_enterRelays(&BODY_CTX->txHashBuilder); - subctx->state = STAKE_POOL_REGISTRATION_RELAYS; - - if (subctx->numRelays > 0) { - break; - } - - // intentional fallthrough - - case STAKE_POOL_REGISTRATION_RELAYS: - ASSERT(subctx->currentRelay == subctx->numRelays); - - subctx->state = STAKE_POOL_REGISTRATION_METADATA; - break; - - case STAKE_POOL_REGISTRATION_METADATA: - subctx->state = STAKE_POOL_REGISTRATION_CONFIRM; - break; - - case STAKE_POOL_REGISTRATION_CONFIRM: - subctx->state = STAKE_POOL_REGISTRATION_FINISHED; - break; - - default: - ASSERT(false); - } - - TRACE("Advancing pool registration certificate state to: %d", subctx->state); -} - - // ============================== INIT ============================== -enum { - HANDLE_POOL_INIT_STEP_DISPLAY = 6100, - HANDLE_POOL_INIT_STEP_RESPOND, - HANDLE_POOL_INIT_STEP_INVALID, -} ; - -static void handlePoolInit_ui_runStep() -{ - pool_registration_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = handlePoolInit_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_POOL_INIT_STEP_DISPLAY) { - ui_displayPaginatedText( - "Pool registration", - "certificate", - this_fn - ); - } - UI_STEP(HANDLE_POOL_INIT_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_POOL_INIT_STEP_INVALID); -} - __noinline_due_to_stack__ static void signTxPoolRegistration_handleInitAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) { @@ -239,47 +149,6 @@ static void _toPoolKeyHash(const pool_id_t* poolId, uint8_t* poolKeyHash) } } -enum { - HANDLE_POOL_KEY_STEP_DISPLAY_POOL_PATH = 6200, - HANDLE_POOL_KEY_STEP_DISPLAY_POOL_ID, - HANDLE_POOL_KEY_STEP_RESPOND, - HANDLE_POOL_KEY_STEP_INVALID, -} ; - -static void handlePoolKey_ui_runStep() -{ - pool_registration_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = handlePoolKey_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_POOL_KEY_STEP_DISPLAY_POOL_PATH) { - ui_displayPathScreen( - "Pool ID path", - &subctx->stateData.poolId.path, - this_fn - ); - } - UI_STEP(HANDLE_POOL_KEY_STEP_DISPLAY_POOL_ID) { - uint8_t poolKeyHash[POOL_KEY_HASH_LENGTH] = {0}; - _toPoolKeyHash(&subctx->stateData.poolId, poolKeyHash); - - ui_displayBech32Screen( - "Pool ID", - "pool", - poolKeyHash, SIZEOF(poolKeyHash), - this_fn - ); - } - UI_STEP(HANDLE_POOL_KEY_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_POOL_KEY_STEP_INVALID); -} - static void _parsePoolId(read_view_t* view) { pool_id_t* key = &accessSubcontext()->stateData.poolId; @@ -380,36 +249,6 @@ static void signTxPoolRegistration_handlePoolKeyAPDU(const uint8_t* wireDataBuff // ============================== VRF KEY HASH ============================== -enum { - HANDLE_POOL_VRF_KEY_STEP_DISPLAY = 6300, - HANDLE_POOL_VRF_KEY_STEP_RESPOND, - HANDLE_POOL_VRF_KEY_STEP_INVALID, -} ; - -static void handlePoolVrfKey_ui_runStep() -{ - pool_registration_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = handlePoolVrfKey_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_POOL_VRF_KEY_STEP_DISPLAY) { - ui_displayBech32Screen( - "VRF key hash", - "vrf_vk", - subctx->stateData.vrfKeyHash, SIZEOF(subctx->stateData.vrfKeyHash), - this_fn - ); - } - UI_STEP(HANDLE_POOL_VRF_KEY_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_POOL_VRF_KEY_STEP_INVALID); -} - __noinline_due_to_stack__ static void signTxPoolRegistration_handleVrfKeyAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) { @@ -465,51 +304,6 @@ static void signTxPoolRegistration_handleVrfKeyAPDU(const uint8_t* wireDataBuffe // ============================== POOL FINANCIALS ============================== -enum { - HANDLE_POOL_FINANCIALS_STEP_DISPLAY_PLEDGE = 6400, - HANDLE_POOL_FINANCIALS_STEP_DISPLAY_COST, - HANDLE_POOL_FINANCIALS_STEP_DISPLAY_MARGIN, - HANDLE_POOL_FINANCIALS_STEP_RESPOND, - HANDLE_POOL_FINANCIALS_STEP_INVALID, -} ; - -static void handlePoolFinancials_ui_runStep() -{ - pool_registration_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = handlePoolFinancials_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_POOL_FINANCIALS_STEP_DISPLAY_PLEDGE) { - ui_displayAdaAmountScreen( - "Pledge", - subctx->stateData.pledge, - this_fn - ); - } - UI_STEP(HANDLE_POOL_FINANCIALS_STEP_DISPLAY_COST) { - ui_displayAdaAmountScreen( - "Cost", - subctx->stateData.cost, - this_fn - ); - } - UI_STEP(HANDLE_POOL_FINANCIALS_STEP_DISPLAY_MARGIN) { - ui_displayPoolMarginScreen( - subctx->stateData.marginNumerator, - subctx->stateData.marginDenominator, - this_fn - ); - } - UI_STEP(HANDLE_POOL_FINANCIALS_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_POOL_FINANCIALS_STEP_INVALID); -} - __noinline_due_to_stack__ static void signTxPoolRegistration_handlePoolFinancialsAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) { @@ -573,35 +367,6 @@ static void signTxPoolRegistration_handlePoolFinancialsAPDU(const uint8_t* wireD // ============================== POOL REWARD ACCOUNT ============================== -enum { - HANDLE_POOL_REWARD_ACCOUNT_STEP_DISPLAY = 6500, - HANDLE_POOL_REWARD_ACCOUNT_STEP_RESPOND, - HANDLE_POOL_REWARD_ACCOUNT_STEP_INVALID, -}; - -static void handlePoolRewardAccount_ui_runStep() -{ - pool_registration_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = handlePoolRewardAccount_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_POOL_REWARD_ACCOUNT_STEP_DISPLAY) { - ui_displayRewardAccountScreen( - &subctx->stateData.poolRewardAccount, - commonTxData->networkId, - this_fn - ); - } - UI_STEP(HANDLE_POOL_REWARD_ACCOUNT_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_POOL_REWARD_ACCOUNT_STEP_INVALID); -} - static void _parsePoolRewardAccount(read_view_t* view) { reward_account_t* rewardAccount = &accessSubcontext()->stateData.poolRewardAccount; @@ -690,35 +455,6 @@ static void signTxPoolRegistration_handleRewardAccountAPDU(const uint8_t* wireDa // ============================== OWNER ============================== -enum { - HANDLE_OWNER_STEP_DISPLAY = 6600, - HANDLE_OWNER_STEP_RESPOND, - HANDLE_OWNER_STEP_INVALID, -}; - -static void handleOwner_ui_runStep() -{ - pool_registration_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = handleOwner_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_OWNER_STEP_DISPLAY) { - ui_displayPoolOwnerScreen(&subctx->stateData.owner, subctx->currentOwner, commonTxData->networkId, this_fn); - } - UI_STEP(HANDLE_OWNER_STEP_RESPOND) { - respondSuccessEmptyMsg(); - - subctx->currentOwner++; - if (subctx->currentOwner == subctx->numOwners) { - advanceState(); - } - } - UI_STEP_END(HANDLE_OWNER_STEP_INVALID); -} - __noinline_due_to_stack__ static void _addOwnerToTxHash() { @@ -826,128 +562,6 @@ static void signTxPoolRegistration_handleOwnerAPDU(const uint8_t* wireDataBuffer // ============================== RELAY ============================== -enum { - HANDLE_RELAY_IP_STEP_DISPLAY_NUMBER = 6700, - HANDLE_RELAY_IP_STEP_DISPLAY_IPV4, - HANDLE_RELAY_IP_STEP_DISPLAY_IPV6, - HANDLE_RELAY_IP_STEP_DISPLAY_PORT, - HANDLE_RELAY_IP_STEP_RESPOND, - HANDLE_RELAY_IP_STEP_INVALID, -}; - -static void handleRelay_ip_ui_runStep() -{ - pool_registration_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = handleRelay_ip_ui_runStep; - - pool_relay_t* relay = &subctx->stateData.relay; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_RELAY_IP_STEP_DISPLAY_NUMBER) { - ui_displayPoolRelayScreen( - relay, - subctx->currentRelay, - this_fn - ); - } - UI_STEP(HANDLE_RELAY_IP_STEP_DISPLAY_IPV4) { - ui_displayIpv4Screen( - &relay->ipv4, - this_fn - ); - } - UI_STEP(HANDLE_RELAY_IP_STEP_DISPLAY_IPV6) { - ui_displayIpv6Screen( - &relay->ipv6, - this_fn - ); - } - UI_STEP(HANDLE_RELAY_IP_STEP_DISPLAY_PORT) { - ui_displayIpPortScreen( - &relay->port, - this_fn - ); - } - UI_STEP(HANDLE_RELAY_IP_STEP_RESPOND) { - respondSuccessEmptyMsg(); - - subctx->currentRelay++; - TRACE("current relay %d", subctx->currentRelay); - - if (subctx->currentRelay == subctx->numRelays) { - advanceState(); - } - } - UI_STEP_END(HANDLE_RELAY_IP_STEP_INVALID); -} - -enum { - HANDLE_RELAY_DNS_STEP_DISPLAY_NUMBER = 6800, - HANDLE_RELAY_DNS_STEP_DISPLAY_DNSNAME, - HANDLE_RELAY_DNS_STEP_DISPLAY_PORT, - HANDLE_RELAY_DNS_STEP_RESPOND, - HANDLE_RELAY_DNS_STEP_INVALID, -}; - -static void handleRelay_dns_ui_runStep() -{ - pool_registration_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = handleRelay_dns_ui_runStep; - - pool_relay_t* relay = &subctx->stateData.relay; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_RELAY_DNS_STEP_DISPLAY_NUMBER) { - ui_displayPoolRelayScreen( - relay, - subctx->currentRelay, - this_fn - ); - } - UI_STEP(HANDLE_RELAY_DNS_STEP_DISPLAY_DNSNAME) { - char dnsNameStr[1 + DNS_NAME_SIZE_MAX] = {0}; - explicit_bzero(dnsNameStr, SIZEOF(dnsNameStr)); - ASSERT(relay->dnsNameSize <= DNS_NAME_SIZE_MAX); - memmove(dnsNameStr, relay->dnsName, relay->dnsNameSize); - dnsNameStr[relay->dnsNameSize] = '\0'; - ASSERT(strlen(dnsNameStr) == relay->dnsNameSize); - - ui_displayPaginatedText( - "DNS name", - dnsNameStr, - this_fn - ); - } - UI_STEP(HANDLE_RELAY_DNS_STEP_DISPLAY_PORT) { - if (relay->format == RELAY_MULTIPLE_HOST_NAME) { - // nothing to display in this step, so we skip it - UI_STEP_JUMP(HANDLE_RELAY_DNS_STEP_RESPOND); - } - - ui_displayIpPortScreen( - &relay->port, - this_fn - ); - } - UI_STEP(HANDLE_RELAY_DNS_STEP_RESPOND) { - respondSuccessEmptyMsg(); - - subctx->currentRelay++; - TRACE("current relay %d", subctx->currentRelay); - - if (subctx->currentRelay == subctx->numRelays) { - advanceState(); - } - } - UI_STEP_END(HANDLE_RELAY_DNS_STEP_INVALID); -} - static void _parsePort(ipport_t* port, read_view_t* view) { uint8_t isPortGiven = parse_u1be(view); @@ -1126,89 +740,6 @@ static void signTxPoolRegistration_handleRelayAPDU(const uint8_t* wireDataBuffer // ============================== METADATA ============================== -enum { - HANDLE_NULL_METADATA_STEP_DISPLAY = 6900, - HANDLE_NULL_METADATA_STEP_RESPOND, - HANDLE_NULL_METADATA_STEP_INVALID, -}; - -static void handleNullMetadata_ui_runStep() -{ - pool_registration_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = handleNullMetadata_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_NULL_METADATA_STEP_DISPLAY) { - ui_displayPaginatedText( - "No metadata", - "(anonymous pool)", - this_fn - ); - } - UI_STEP(HANDLE_NULL_METADATA_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_NULL_METADATA_STEP_INVALID); -} - -enum { - HANDLE_METADATA_STEP_DISPLAY_URL = 7000, - HANDLE_METADATA_STEP_DISPLAY_HASH, - HANDLE_METADATA_STEP_RESPOND, - HANDLE_METADATA_STEP_INVALID, -}; - -static void handleMetadata_ui_runStep() -{ - pool_registration_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = handleMetadata_ui_runStep; - - pool_metadata_t* md = &subctx->stateData.metadata; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_METADATA_STEP_DISPLAY_URL) { - char metadataUrlStr[1 + POOL_METADATA_URL_LENGTH_MAX] = {0}; - explicit_bzero(metadataUrlStr, SIZEOF(metadataUrlStr)); - ASSERT(md->urlSize <= POOL_METADATA_URL_LENGTH_MAX); - memmove(metadataUrlStr, md->url, md->urlSize); - metadataUrlStr[md->urlSize] = '\0'; - ASSERT(strlen(metadataUrlStr) == md->urlSize); - - ui_displayPaginatedText( - "Pool metadata url", - metadataUrlStr, - this_fn - ); - } - UI_STEP(HANDLE_METADATA_STEP_DISPLAY_HASH) { - char metadataHashHex[1 + 2 * POOL_METADATA_HASH_LENGTH] = {0}; - explicit_bzero(metadataHashHex, SIZEOF(metadataHashHex)); - size_t len = str_formatMetadata( - md->hash, SIZEOF(md->hash), - metadataHashHex, SIZEOF(metadataHashHex) - ); - ASSERT(len + 1 == SIZEOF(metadataHashHex)); - - ui_displayPaginatedText( - "Pool metadata hash", - metadataHashHex, - this_fn - ); - } - UI_STEP(HANDLE_METADATA_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_METADATA_STEP_INVALID); -} - static void handleNullMetadata() { security_policy_t policy = policyForSignTxStakePoolRegistrationNoMetadata(); @@ -1317,64 +848,6 @@ static void signTxPoolRegistration_handlePoolMetadataAPDU(const uint8_t* wireDat // ============================== CONFIRM ============================== -enum { - HANDLE_CONFIRM_STEP_FINAL_NO_OWNERS = 7100, - HANDLE_CONFIRM_STEP_FINAL_NO_RELAYS, - HANDLE_CONFIRM_STEP_FINAL_CONFIRM, - HANDLE_CONFIRM_STEP_RESPOND, - HANDLE_CONFIRM_STEP_INVALID, -}; - -static void signTxPoolRegistration_handleConfirm_ui_runStep() -{ - pool_registration_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTxPoolRegistration_handleConfirm_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - // we display potentially suspicious facts about the certificate - // that have not been explicitly shown to the user before: - // missing owners or relays - UI_STEP(HANDLE_CONFIRM_STEP_FINAL_NO_OWNERS) { - if (subctx->numOwners == 0) { - ui_displayPaginatedText( - "No", - "pool owners", - this_fn - ); - } else { - UI_STEP_JUMP(HANDLE_CONFIRM_STEP_FINAL_NO_RELAYS); - } - } - UI_STEP(HANDLE_CONFIRM_STEP_FINAL_NO_RELAYS) { - bool isOperator = commonTxData->txSigningMode == SIGN_TX_SIGNINGMODE_POOL_REGISTRATION_OPERATOR; - if ((subctx->numRelays == 0) && isOperator) { - ui_displayPaginatedText( - "No", - "pool relays", - this_fn - ); - } else { - UI_STEP_JUMP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM); - } - } - UI_STEP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM) { - ui_displayPrompt( - "Confirm stake", - "pool registration?", - this_fn, - respond_with_user_reject - ); - } - UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_CONFIRM_STEP_INVALID); -} - __noinline_due_to_stack__ static void signTxPoolRegistration_handleConfirmAPDU(const uint8_t* wireDataBuffer MARK_UNUSED, size_t wireDataSize) { diff --git a/src/signTxPoolRegistration_ui.c b/src/signTxPoolRegistration_ui.c new file mode 100644 index 00000000..4ef1ec26 --- /dev/null +++ b/src/signTxPoolRegistration_ui.c @@ -0,0 +1,793 @@ +#include "signTx.h" +#include "signTxPoolRegistration_ui.h" +#include "state.h" +#include "cardano.h" +#include "addressUtilsShelley.h" +#include "keyDerivation.h" +#include "uiHelpers.h" +#include "signTxUtils.h" +#include "txHashBuilder.h" +#include "textUtils.h" +#include "hexUtils.h" +#include "bufView.h" +#include "securityPolicy.h" +#include "signTxPoolRegistration.h" +#include "ipUtils.h" + +#ifdef HAVE_BAGL +#include "uiScreens_bagl.h" +#elif defined(HAVE_NBGL) +#include "uiScreens_nbgl.h" +#endif + +static common_tx_data_t* commonTxData = &(instructionState.signTxContext.commonTxData); + +static pool_registration_context_t* accessSubcontext() +{ + return &BODY_CTX->stageContext.pool_registration_subctx; +} + +static inline void advanceState() +{ + pool_registration_context_t* subctx = accessSubcontext(); + TRACE("Advancing pool registration certificate state from: %d", subctx->state); + + switch (subctx->state) { + + case STAKE_POOL_REGISTRATION_INIT: + subctx->state = STAKE_POOL_REGISTRATION_POOL_KEY; + break; + + case STAKE_POOL_REGISTRATION_POOL_KEY: + subctx->state = STAKE_POOL_REGISTRATION_VRF_KEY; + break; + + case STAKE_POOL_REGISTRATION_VRF_KEY: + subctx->state = STAKE_POOL_REGISTRATION_FINANCIALS; + break; + + case STAKE_POOL_REGISTRATION_FINANCIALS: + subctx->state = STAKE_POOL_REGISTRATION_REWARD_ACCOUNT; + break; + + case STAKE_POOL_REGISTRATION_REWARD_ACCOUNT: + txHashBuilder_addPoolRegistrationCertificate_enterOwners(&BODY_CTX->txHashBuilder); + subctx->state = STAKE_POOL_REGISTRATION_OWNERS; + + if (subctx->numOwners > 0) { + break; + } + + // intentional fallthrough + + case STAKE_POOL_REGISTRATION_OWNERS: + ASSERT(subctx->currentOwner == subctx->numOwners); + + txHashBuilder_addPoolRegistrationCertificate_enterRelays(&BODY_CTX->txHashBuilder); + subctx->state = STAKE_POOL_REGISTRATION_RELAYS; + + if (subctx->numRelays > 0) { + break; + } + + // intentional fallthrough + + case STAKE_POOL_REGISTRATION_RELAYS: + ASSERT(subctx->currentRelay == subctx->numRelays); + + subctx->state = STAKE_POOL_REGISTRATION_METADATA; + break; + + case STAKE_POOL_REGISTRATION_METADATA: + subctx->state = STAKE_POOL_REGISTRATION_CONFIRM; + break; + + case STAKE_POOL_REGISTRATION_CONFIRM: + subctx->state = STAKE_POOL_REGISTRATION_FINISHED; + break; + + default: + ASSERT(false); + } + + TRACE("Advancing pool registration certificate state to: %d", subctx->state); +} + +// ============================== INIT ============================== + +void handlePoolInit_ui_runStep() +{ + pool_registration_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = handlePoolInit_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_POOL_INIT_STEP_DISPLAY) { +#ifdef HAVE_BAGL + ui_displayPaginatedText( + "Pool registration", + "certificate", + this_fn + ); +#elif defined(HAVE_NBGL) + display_prompt( + "Pool registration\ncertificate", + "", + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_POOL_INIT_STEP_RESPOND) { + respondSuccessEmptyMsg(); + advanceState(); + } + UI_STEP_END(HANDLE_POOL_INIT_STEP_INVALID); +} + +// ============================== POOL KEY HASH / ID ============================== + +static void _toPoolKeyHash(const pool_id_t* poolId, uint8_t* poolKeyHash) +{ + switch (poolId->keyReferenceType) { + + case KEY_REFERENCE_HASH: { + STATIC_ASSERT(SIZEOF(poolId->hash) == POOL_KEY_HASH_LENGTH, "wrong pool key hash length"); + memmove(poolKeyHash, poolId->hash, POOL_KEY_HASH_LENGTH); + break; + } + case KEY_REFERENCE_PATH: { + bip44_pathToKeyHash(&poolId->path, poolKeyHash, POOL_KEY_HASH_LENGTH); + break; + } + default: + ASSERT(false); + } +} + +void handlePoolKey_ui_runStep() +{ + pool_registration_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = handlePoolKey_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_POOL_KEY_STEP_DISPLAY_POOL_PATH) { +#ifdef HAVE_BAGL + ui_displayPathScreen( + "Pool ID path", + &subctx->stateData.poolId.path, + this_fn + ); +#elif defined(HAVE_NBGL) + char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; + ui_getPathScreen( + pathStr, SIZEOF(pathStr), + &subctx->stateData.poolId.path + ); + fill_and_display_if_required( + "Pool ID path", + pathStr, + this_fn, + respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_POOL_KEY_STEP_DISPLAY_POOL_ID) { + uint8_t poolKeyHash[POOL_KEY_HASH_LENGTH] = {0}; + _toPoolKeyHash(&subctx->stateData.poolId, poolKeyHash); + +#ifdef HAVE_BAGL + ui_displayBech32Screen( + "Pool ID", + "pool", + poolKeyHash, SIZEOF(poolKeyHash), + this_fn + ); +#elif defined(HAVE_NBGL) + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen( + encodedStr, SIZEOF(encodedStr), + "pool", + poolKeyHash, SIZEOF(poolKeyHash) + ); + + fill_and_display_if_required( + "Pool ID", + encodedStr, + this_fn, + respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_POOL_KEY_STEP_RESPOND) { + respondSuccessEmptyMsg(); + advanceState(); + } + UI_STEP_END(HANDLE_POOL_KEY_STEP_INVALID); +} + +// ============================== VRF KEY HASH ============================== + +void handlePoolVrfKey_ui_runStep() +{ + pool_registration_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = handlePoolVrfKey_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_POOL_VRF_KEY_STEP_DISPLAY) { +#ifdef HAVE_BAGL + ui_displayBech32Screen( + "VRF key hash", + "vrf_vk", + subctx->stateData.vrfKeyHash, SIZEOF(subctx->stateData.vrfKeyHash), + this_fn + ); +#elif defined(HAVE_NBGL) + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen( + encodedStr, SIZEOF(encodedStr), + "vrf_vk", + subctx->stateData.vrfKeyHash, SIZEOF(subctx->stateData.vrfKeyHash)); + + fill_and_display_if_required( + "VRF key hash", + encodedStr, + this_fn, + respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_POOL_VRF_KEY_STEP_RESPOND) { + respondSuccessEmptyMsg(); + advanceState(); + } + UI_STEP_END(HANDLE_POOL_VRF_KEY_STEP_INVALID); +} + +// ============================== POOL FINANCIALS ============================== + +void handlePoolFinancials_ui_runStep() +{ + pool_registration_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = handlePoolFinancials_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_POOL_FINANCIALS_STEP_DISPLAY_PLEDGE) { +#ifdef HAVE_BAGL + ui_displayAdaAmountScreen( + "Pledge", + subctx->stateData.pledge, + this_fn + ); +#elif defined(HAVE_NBGL) + char adaAmountStr[50] = {0}; + ui_getAdaAmountScreen( + adaAmountStr, SIZEOF(adaAmountStr), + subctx->stateData.pledge + ); + + fill_and_display_if_required( + "Pledge", + adaAmountStr, + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_POOL_FINANCIALS_STEP_DISPLAY_COST) { +#ifdef HAVE_BAGL + ui_displayAdaAmountScreen( + "Cost", + subctx->stateData.cost, + this_fn + ); +#elif defined(HAVE_NBGL) + char adaAmountStr[50] = {0}; + ui_getAdaAmountScreen( + adaAmountStr, SIZEOF(adaAmountStr), + subctx->stateData.cost + ); + + fill_and_display_if_required( + "Cost", + adaAmountStr, + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_POOL_FINANCIALS_STEP_DISPLAY_MARGIN) { +#ifdef HAVE_BAGL + ui_displayPoolMarginScreen( + subctx->stateData.marginNumerator, + subctx->stateData.marginDenominator, + this_fn + ); +#elif defined(HAVE_NBGL) + char marginStr[20] = {0}; + ui_getPoolMarginScreen( + marginStr, SIZEOF(marginStr), + subctx->stateData.marginNumerator, + subctx->stateData.marginDenominator + ); + fill_and_display_if_required( + "Profit margin", + marginStr, + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_POOL_FINANCIALS_STEP_RESPOND) { + respondSuccessEmptyMsg(); + advanceState(); + } + UI_STEP_END(HANDLE_POOL_FINANCIALS_STEP_INVALID); +} + +// ============================== POOL REWARD ACCOUNT ============================== + +static void handlePoolRewardAccount_ui_runStep_cb(void) { + force_display(handlePoolRewardAccount_ui_runStep, respond_with_user_reject); +} + +void handlePoolRewardAccount_ui_runStep() +{ + pool_registration_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = handlePoolRewardAccount_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_POOL_REWARD_ACCOUNT_STEP_DISPLAY) { +#ifdef HAVE_BAGL + ui_displayRewardAccountScreen( + &subctx->stateData.poolRewardAccount, + commonTxData->networkId, + this_fn + ); +#elif defined(HAVE_NBGL) + char firstLine[32] = {0}; + char secondLine[BIP44_PATH_STRING_SIZE_MAX + MAX_HUMAN_REWARD_ACCOUNT_SIZE + 2] = {0}; + ui_getRewardAccountScreen( + firstLine, SIZEOF(firstLine), + secondLine, SIZEOF(secondLine), + &subctx->stateData.poolRewardAccount, + commonTxData->networkId + ); + fill_and_display_if_required( + firstLine, + secondLine, + handlePoolRewardAccount_ui_runStep_cb, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_POOL_REWARD_ACCOUNT_STEP_RESPOND) { + respondSuccessEmptyMsg(); + advanceState(); + } + UI_STEP_END(HANDLE_POOL_REWARD_ACCOUNT_STEP_INVALID); +} + +// ============================== OWNER ============================== + +void handleOwner_ui_runStep() +{ + pool_registration_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = handleOwner_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_OWNER_STEP_DISPLAY) { +#ifdef HAVE_BAGL + ui_displayPoolOwnerScreen(&subctx->stateData.owner, subctx->currentOwner, commonTxData->networkId, this_fn); +#elif defined(HAVE_NBGL) + char firstLine[32] = {0}; + char secondLine[BIP44_PATH_STRING_SIZE_MAX + MAX_HUMAN_REWARD_ACCOUNT_SIZE + 2] = {0}; + ui_getPoolOwnerScreen( + firstLine, SIZEOF(firstLine), + secondLine, SIZEOF(secondLine), + &subctx->stateData.owner, subctx->currentOwner, + commonTxData->networkId + ); + fill_and_display_if_required( + firstLine, + secondLine, + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_OWNER_STEP_RESPOND) { + respondSuccessEmptyMsg(); + + subctx->currentOwner++; + if (subctx->currentOwner == subctx->numOwners) { + advanceState(); + } + } + UI_STEP_END(HANDLE_OWNER_STEP_INVALID); +} + +// ============================== RELAY ============================== + +void handleRelay_ip_ui_runStep() +{ + pool_registration_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = handleRelay_ip_ui_runStep; + + pool_relay_t* relay = &subctx->stateData.relay; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_RELAY_IP_STEP_DISPLAY_NUMBER) { +#ifdef HAVE_BAGL + ui_displayPoolRelayScreen( + relay, + subctx->currentRelay, + this_fn + ); +#elif defined(HAVE_NBGL) + char line[20] = {0}; + ui_getPoolRelayScreen( + line, SIZEOF(line), + subctx->currentRelay + ); + fill_and_display_if_required("Relay index", line, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_RELAY_IP_STEP_DISPLAY_IPV4) { +#ifdef HAVE_BAGL + ui_displayIpv4Screen( + &relay->ipv4, + this_fn + ); +#elif defined(HAVE_NBGL) + char ipStr[IPV4_STR_SIZE_MAX + 1] = {0}; + ui_getIpv4Screen( + ipStr, SIZEOF(ipStr), + &relay->ipv4 + ); + fill_and_display_if_required( + "IPv4 address", + ipStr, + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_RELAY_IP_STEP_DISPLAY_IPV6) { +#ifdef HAVE_BAGL + ui_displayIpv6Screen( + &relay->ipv6, + this_fn + ); +#elif defined(HAVE_NBGL) + char ipStr[IPV6_STR_SIZE_MAX + 1] = {0}; + ui_getIpv6Screen( + ipStr, SIZEOF(ipStr), + &relay->ipv6 + ); + fill_and_display_if_required( + "IPv6 address", + ipStr, + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_RELAY_IP_STEP_DISPLAY_PORT) { +#ifdef HAVE_BAGL + ui_displayIpPortScreen( + &relay->port, + this_fn + ); +#elif defined(HAVE_NBGL) + char portStr[1 + (sizeof "65536")] = {0}; + ui_getIpPortScreen( + portStr, SIZEOF(portStr), + &relay->port + ); + fill_and_display_if_required( + "Port", + portStr, + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_RELAY_IP_STEP_RESPOND) { + respondSuccessEmptyMsg(); + + subctx->currentRelay++; + TRACE("current relay %d", subctx->currentRelay); + + if (subctx->currentRelay == subctx->numRelays) { + advanceState(); + } + } + UI_STEP_END(HANDLE_RELAY_IP_STEP_INVALID); +} + +void handleRelay_dns_ui_runStep() +{ + pool_registration_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = handleRelay_dns_ui_runStep; + + pool_relay_t* relay = &subctx->stateData.relay; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_RELAY_DNS_STEP_DISPLAY_NUMBER) { +#ifdef HAVE_BAGL + ui_displayPoolRelayScreen( + relay, + subctx->currentRelay, + this_fn + ); +#elif defined(HAVE_NBGL) + char line[20] = {0}; + ui_getPoolRelayScreen( + line, SIZEOF(line), + subctx->currentRelay + ); + fill_and_display_if_required("Relay index", line, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_RELAY_DNS_STEP_DISPLAY_DNSNAME) { + char dnsNameStr[1 + DNS_NAME_SIZE_MAX] = {0}; + explicit_bzero(dnsNameStr, SIZEOF(dnsNameStr)); + ASSERT(relay->dnsNameSize <= DNS_NAME_SIZE_MAX); + memmove(dnsNameStr, relay->dnsName, relay->dnsNameSize); + dnsNameStr[relay->dnsNameSize] = '\0'; + ASSERT(strlen(dnsNameStr) == relay->dnsNameSize); + +#ifdef HAVE_BAGL + ui_displayPaginatedText( + "DNS name", + dnsNameStr, + this_fn + ); +#elif defined(HAVE_NBGL) + fill_and_display_if_required( + "DNS name", + dnsNameStr, + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_RELAY_DNS_STEP_DISPLAY_PORT) { + if (relay->format == RELAY_MULTIPLE_HOST_NAME) { + // nothing to display in this step, so we skip it + UI_STEP_JUMP(HANDLE_RELAY_DNS_STEP_RESPOND); + } + +#ifdef HAVE_BAGL + ui_displayIpPortScreen( + &relay->port, + this_fn + ); +#elif defined(HAVE_NBGL) + char portStr[1 + (sizeof "65536")] = {0}; + ui_getIpPortScreen( + portStr, SIZEOF(portStr), + &relay->port + ); + fill_and_display_if_required( + "Port", + portStr, + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_RELAY_DNS_STEP_RESPOND) { + respondSuccessEmptyMsg(); + + subctx->currentRelay++; + TRACE("current relay %d", subctx->currentRelay); + + if (subctx->currentRelay == subctx->numRelays) { + advanceState(); + } + } + UI_STEP_END(HANDLE_RELAY_DNS_STEP_INVALID); +} + + +// ============================== METADATA ============================== + +void handleNullMetadata_ui_runStep() +{ + pool_registration_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = handleNullMetadata_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_NULL_METADATA_STEP_DISPLAY) { +#ifdef HAVE_BAGL + ui_displayPaginatedText( + "No metadata", + "(anonymous pool)", + this_fn + ); +#elif defined(HAVE_NBGL) + fill_and_display_if_required( + "Metadata", + "None: anymous pool", + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_NULL_METADATA_STEP_RESPOND) { + respondSuccessEmptyMsg(); + advanceState(); + } + UI_STEP_END(HANDLE_NULL_METADATA_STEP_INVALID); +} + +void handleMetadata_ui_runStep() +{ + pool_registration_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = handleMetadata_ui_runStep; + + pool_metadata_t* md = &subctx->stateData.metadata; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_METADATA_STEP_DISPLAY_URL) { + char metadataUrlStr[1 + POOL_METADATA_URL_LENGTH_MAX] = {0}; + explicit_bzero(metadataUrlStr, SIZEOF(metadataUrlStr)); + ASSERT(md->urlSize <= POOL_METADATA_URL_LENGTH_MAX); + memmove(metadataUrlStr, md->url, md->urlSize); + metadataUrlStr[md->urlSize] = '\0'; + ASSERT(strlen(metadataUrlStr) == md->urlSize); + +#ifdef HAVE_BAGL + ui_displayPaginatedText( + "Pool metadata url", + metadataUrlStr, + this_fn + ); +#elif defined(HAVE_NBGL) + fill_and_display_if_required( + "Pool metadata url", + metadataUrlStr, + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_METADATA_STEP_DISPLAY_HASH) { + char metadataHashHex[1 + 2 * POOL_METADATA_HASH_LENGTH] = {0}; + explicit_bzero(metadataHashHex, SIZEOF(metadataHashHex)); + size_t len = str_formatMetadata( + md->hash, SIZEOF(md->hash), + metadataHashHex, SIZEOF(metadataHashHex) + ); + ASSERT(len + 1 == SIZEOF(metadataHashHex)); + +#ifdef HAVE_BAGL + ui_displayPaginatedText( + "Pool metadata hash", + metadataHashHex, + this_fn + ); +#elif defined(HAVE_NBGL) + fill_and_display_if_required( + "Pool metadata hash", + metadataHashHex, + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_METADATA_STEP_RESPOND) { + respondSuccessEmptyMsg(); + advanceState(); + } + UI_STEP_END(HANDLE_METADATA_STEP_INVALID); +} + +// ============================== CONFIRM ============================== + +void signTxPoolRegistration_handleConfirm_ui_runStep() +{ + pool_registration_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = signTxPoolRegistration_handleConfirm_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + // we display potentially suspicious facts about the certificate + // that have not been explicitly shown to the user before: + // missing owners or relays + UI_STEP(HANDLE_CONFIRM_STEP_FINAL_NO_OWNERS) { + if (subctx->numOwners == 0) { +#ifdef HAVE_BAGL + ui_displayPaginatedText( + "No", + "pool owners", + this_fn + ); +#elif defined(HAVE_NBGL) + fill_and_display_if_required( + "Pool owners", + "None", + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } else { + UI_STEP_JUMP(HANDLE_CONFIRM_STEP_FINAL_NO_RELAYS); + } + } + UI_STEP(HANDLE_CONFIRM_STEP_FINAL_NO_RELAYS) { + bool isOperator = commonTxData->txSigningMode == SIGN_TX_SIGNINGMODE_POOL_REGISTRATION_OPERATOR; + if ((subctx->numRelays == 0) && isOperator) { +#ifdef HAVE_BAGL + ui_displayPaginatedText( + "No", + "pool relays", + this_fn + ); +#elif defined(HAVE_NBGL) + fill_and_display_if_required( + "Pool relays", + "None", + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } else { + UI_STEP_JUMP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM); + } + } + UI_STEP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM) { +#ifdef HAVE_BAGL + ui_displayPrompt( + "Confirm stake", + "pool registration?", + this_fn, + respond_with_user_reject + ); +#elif defined(HAVE_NBGL) + display_confirmation( + "Confirm stake pool\nregistration", + "", + "STAKE POOL\nREGISTERED", + "Stake pool\nrejected", + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { + respondSuccessEmptyMsg(); + advanceState(); + } + UI_STEP_END(HANDLE_CONFIRM_STEP_INVALID); +} diff --git a/src/signTxPoolRegistration_ui.h b/src/signTxPoolRegistration_ui.h new file mode 100644 index 00000000..b155805f --- /dev/null +++ b/src/signTxPoolRegistration_ui.h @@ -0,0 +1,125 @@ +#ifndef H_CARDANO_APP_SIGN_TX_POOL_REGISATRATION_UI +#define H_CARDANO_APP_SIGN_TX_POOL_REGISATRATION_UI + +// ============================== INIT ============================== + +enum { + HANDLE_POOL_INIT_STEP_DISPLAY = 6100, + HANDLE_POOL_INIT_STEP_RESPOND, + HANDLE_POOL_INIT_STEP_INVALID, +} ; + +void handlePoolInit_ui_runStep(); + +// ============================== POOL KEY HASH / ID ============================== + +enum { + HANDLE_POOL_KEY_STEP_DISPLAY_POOL_PATH = 6200, + HANDLE_POOL_KEY_STEP_DISPLAY_POOL_ID, + HANDLE_POOL_KEY_STEP_RESPOND, + HANDLE_POOL_KEY_STEP_INVALID, +} ; + +void handlePoolKey_ui_runStep(); + +// ============================== VRF KEY HASH ============================== + +enum { + HANDLE_POOL_VRF_KEY_STEP_DISPLAY = 6300, + HANDLE_POOL_VRF_KEY_STEP_RESPOND, + HANDLE_POOL_VRF_KEY_STEP_INVALID, +} ; + +void handlePoolVrfKey_ui_runStep(); + + +// ============================== POOL FINANCIALS ============================== + +enum { + HANDLE_POOL_FINANCIALS_STEP_DISPLAY_PLEDGE = 6400, + HANDLE_POOL_FINANCIALS_STEP_DISPLAY_COST, + HANDLE_POOL_FINANCIALS_STEP_DISPLAY_MARGIN, + HANDLE_POOL_FINANCIALS_STEP_RESPOND, + HANDLE_POOL_FINANCIALS_STEP_INVALID, +} ; + +void handlePoolFinancials_ui_runStep(); + + +// ============================== POOL REWARD ACCOUNT ============================== + +enum { + HANDLE_POOL_REWARD_ACCOUNT_STEP_DISPLAY = 6500, + HANDLE_POOL_REWARD_ACCOUNT_STEP_RESPOND, + HANDLE_POOL_REWARD_ACCOUNT_STEP_INVALID, +}; + +void handlePoolRewardAccount_ui_runStep(); + + +// ============================== OWNER ============================== + +enum { + HANDLE_OWNER_STEP_DISPLAY = 6600, + HANDLE_OWNER_STEP_RESPOND, + HANDLE_OWNER_STEP_INVALID, +}; + +void handleOwner_ui_runStep(); + + +// ============================== RELAY ============================== + +enum { + HANDLE_RELAY_IP_STEP_DISPLAY_NUMBER = 6700, + HANDLE_RELAY_IP_STEP_DISPLAY_IPV4, + HANDLE_RELAY_IP_STEP_DISPLAY_IPV6, + HANDLE_RELAY_IP_STEP_DISPLAY_PORT, + HANDLE_RELAY_IP_STEP_RESPOND, + HANDLE_RELAY_IP_STEP_INVALID, +}; + +void handleRelay_ip_ui_runStep(); + +enum { + HANDLE_RELAY_DNS_STEP_DISPLAY_NUMBER = 6800, + HANDLE_RELAY_DNS_STEP_DISPLAY_DNSNAME, + HANDLE_RELAY_DNS_STEP_DISPLAY_PORT, + HANDLE_RELAY_DNS_STEP_RESPOND, + HANDLE_RELAY_DNS_STEP_INVALID, +}; + +void handleRelay_dns_ui_runStep(); + + +// ============================== METADATA ============================== + +enum { + HANDLE_NULL_METADATA_STEP_DISPLAY = 6900, + HANDLE_NULL_METADATA_STEP_RESPOND, + HANDLE_NULL_METADATA_STEP_INVALID, +}; + +void handleNullMetadata_ui_runStep(); + +enum { + HANDLE_METADATA_STEP_DISPLAY_URL = 7000, + HANDLE_METADATA_STEP_DISPLAY_HASH, + HANDLE_METADATA_STEP_RESPOND, + HANDLE_METADATA_STEP_INVALID, +}; + +void handleMetadata_ui_runStep(); + +// ============================== CONFIRM ============================== + +enum { + HANDLE_CONFIRM_STEP_FINAL_NO_OWNERS = 7100, + HANDLE_CONFIRM_STEP_FINAL_NO_RELAYS, + HANDLE_CONFIRM_STEP_FINAL_CONFIRM, + HANDLE_CONFIRM_STEP_RESPOND, + HANDLE_CONFIRM_STEP_INVALID, +}; + +void signTxPoolRegistration_handleConfirm_ui_runStep(); +#endif // H_CARDANO_APP_SIGN_TX_POOL_REGISATRATION_UI From 90f26410e4e916be68dad3f5907eee828c6d5867 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 19 Oct 2022 10:46:01 +0200 Subject: [PATCH 016/105] getPublicKeys: update for stax --- src/getPublicKeys.c | 132 ++----------------------- src/getPublicKeys.h | 1 + src/getPublicKeys_ui.c | 212 +++++++++++++++++++++++++++++++++++++++++ src/getPublicKeys_ui.h | 24 +++++ 4 files changed, 245 insertions(+), 124 deletions(-) create mode 100644 src/getPublicKeys_ui.c create mode 100644 src/getPublicKeys_ui.h diff --git a/src/getPublicKeys.c b/src/getPublicKeys.c index bd537ab3..dae60f1e 100644 --- a/src/getPublicKeys.c +++ b/src/getPublicKeys.c @@ -1,8 +1,14 @@ #include "state.h" #include "securityPolicy.h" #include "uiHelpers.h" -#include "uiScreens.h" #include "getPublicKeys.h" +#include "getPublicKeys_ui.h" + +#ifdef HAVE_BAGL +#include "uiScreens_bagl.h" +#elif defined(HAVE_NBGL) +#include "uiScreens_nbgl.h" +#endif static int16_t RESPONSE_READY_MAGIC = 23456; @@ -27,86 +33,10 @@ static void parsePath(read_view_t* view) PRINTF("\n"); } -static void advanceStage() -{ - TRACE("Advancing from stage: %d", ctx->stage); - - switch (ctx->stage) { - - case GET_KEYS_STAGE_INIT: - ctx->stage = GET_KEYS_STAGE_GET_KEYS; - - if (ctx->numPaths > 1) { - // there are more paths to be received - // so we don't want to advance beyond GET_KEYS_STAGE_GET_KEYS - break; - } - - // intentional fallthrough - - case GET_KEYS_STAGE_GET_KEYS: - ASSERT(ctx->currentPath == ctx->numPaths); - ctx->stage = GET_KEYS_STAGE_NONE; - ui_idle(); // we are done with this key export - break; - - case SIGN_STAGE_NONE: - default: - ASSERT(false); - } -} - // ============================== derivation and UI state machine for one key ============================== -enum { - GET_KEY_UI_STEP_WARNING = 200, - GET_KEY_UI_STEP_DISPLAY, - GET_KEY_UI_STEP_CONFIRM, - GET_KEY_UI_STEP_RESPOND, -} ; - -static void getPublicKeys_respondOneKey_ui_runStep() -{ - TRACE("UI step %d", ctx->ui_step); - ui_callback_fn_t* this_fn = getPublicKeys_respondOneKey_ui_runStep; - - UI_STEP_BEGIN(ctx->ui_step, this_fn); - UI_STEP(GET_KEY_UI_STEP_WARNING) { - ui_displayPaginatedText( - "Unusual request", - "Proceed with care", - this_fn - ); - } - UI_STEP(GET_KEY_UI_STEP_DISPLAY) { - ui_displayGetPublicKeyPathScreen(&ctx->pathSpec, this_fn); - } - UI_STEP(GET_KEY_UI_STEP_CONFIRM) { - ui_displayPrompt( - "Confirm export", - "public key?", - this_fn, - respond_with_user_reject - ); - } - UI_STEP(GET_KEY_UI_STEP_RESPOND) { - ASSERT(ctx->responseReadyMagic == RESPONSE_READY_MAGIC); - - io_send_buf(SUCCESS, (uint8_t*) &ctx->extPubKey, SIZEOF(ctx->extPubKey)); - ctx->responseReadyMagic = 0; // just for safety - ui_displayBusy(); // displays dots, called only after I/O to avoid freezing - - ctx->currentPath++; - TRACE("Current path: %u / %u", ctx->currentPath, ctx->numPaths); - - if (ctx->currentPath == 1 || ctx->currentPath == ctx->numPaths) - advanceStage(); - } - UI_STEP_END(UI_STEP_NONE); -} - // derive the key described by ctx->pathSpec and run the ui state machine accordingly -static void runGetOnePublicKeyUIFlow() +void runGetOnePublicKeyUIFlow() { ASSERT(ctx->ui_step == UI_STEP_NONE); // make sure no ui state machine is running @@ -143,52 +73,6 @@ static void runGetOnePublicKeyUIFlow() // ============================== INIT ============================== -enum { - HANDLE_INIT_UI_STEP_CONFIRM = 100, - HANDLE_INIT_UI_STEP_RESPOND, // WARNING: this must be the last valid step, see below -} ; - -static void getPublicKeys_handleInit_ui_runStep() -{ - TRACE("UI step %d", ctx->ui_step); - ui_callback_fn_t* this_fn = getPublicKeys_handleInit_ui_runStep; - - UI_STEP_BEGIN(ctx->ui_step, this_fn); - UI_STEP(HANDLE_INIT_UI_STEP_CONFIRM) { - char secondLine[100] = {0}; - explicit_bzero(secondLine, SIZEOF(secondLine)); - STATIC_ASSERT(sizeof(ctx->numPaths) <= sizeof(unsigned), "oversized type for %u"); - STATIC_ASSERT(!IS_SIGNED(ctx->numPaths), "signed type for %u"); - snprintf(secondLine, SIZEOF(secondLine), "%u public keys?", ctx->numPaths); - // make sure all the information is displayed to the user - ASSERT(strlen(secondLine) + 1 < SIZEOF(secondLine)); - - ui_displayPrompt( - "Confirm export", - secondLine, - this_fn, - respond_with_user_reject - ); - } - UI_STEP(HANDLE_INIT_UI_STEP_RESPOND) { - ctx->ui_step = UI_STEP_NONE; // we are finished with this UI state machine - - runGetOnePublicKeyUIFlow(); // run another UI state machine - - // This return statement is needed to bail out from this UI state machine - // which would otherwise be in conflict with the (async) UI state - // machine triggered by promptAndRespondOneKey. - - // Those two machines share the ctx->ui_state variable. - // Without the return statement, UI_STEP_END would overwrite it. - - // WARNING: This works under the assumption that HANDLE_INIT_UI_STEP_RESPOND - // is a terminal state of this UI state machine! - return; - } - UI_STEP_END(UI_STEP_NONE); -} - static void getPublicKeys_handleInitAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) { { diff --git a/src/getPublicKeys.h b/src/getPublicKeys.h index ec673832..ca02fa8e 100644 --- a/src/getPublicKeys.h +++ b/src/getPublicKeys.h @@ -30,4 +30,5 @@ typedef struct { handler_fn_t getPublicKeys_handleAPDU; +void runGetOnePublicKeyUIFlow(); #endif // H_CARDANO_APP_GET_PUBLIC_KEYS diff --git a/src/getPublicKeys_ui.c b/src/getPublicKeys_ui.c new file mode 100644 index 00000000..aae00f82 --- /dev/null +++ b/src/getPublicKeys_ui.c @@ -0,0 +1,212 @@ +#include "state.h" +#include "securityPolicy.h" +#include "uiHelpers.h" +#include "getPublicKeys.h" +#include "getPublicKeys_ui.h" + +#ifdef HAVE_BAGL +#include "uiScreens_bagl.h" +#elif defined(HAVE_NBGL) +#include "nbgl_use_case.h" +#include "uiScreens_nbgl.h" +#endif + +static int16_t RESPONSE_READY_MAGIC = 23456; + +static ins_get_keys_context_t* ctx = &(instructionState.getKeysContext); + +// ctx->ui_state is shared between the intertwined UI state machines below +// it should be set to this value at the beginning and after a UI state machine is finished +static int UI_STEP_NONE = 0; + +static void advanceStage() +{ + TRACE("Advancing from stage: %d", ctx->stage); + + switch (ctx->stage) { + + case GET_KEYS_STAGE_INIT: + ctx->stage = GET_KEYS_STAGE_GET_KEYS; + + if (ctx->numPaths > 1) { + // there are more paths to be received + // so we don't want to advance beyond GET_KEYS_STAGE_GET_KEYS + break; + } + + // intentional fallthrough + + case GET_KEYS_STAGE_GET_KEYS: + ASSERT(ctx->currentPath == ctx->numPaths); + ctx->stage = GET_KEYS_STAGE_NONE; + ui_idle(); // we are done with this key export + break; + + case SIGN_STAGE_NONE: + default: + ASSERT(false); + } +} + +// ============================== derivation and UI state machine for one key ============================== + +#ifdef HAVE_NBGL +static void getPublicKeys_respondOneKey_ui_cb(void) { + char line1[30] = {0}; + char pathStr[MAX(160,BIP44_PATH_STRING_SIZE_MAX + 1)] = {0}; + ui_getPublicKeyPathScreen( + line1, SIZEOF(line1), + pathStr, SIZEOF(pathStr), + &ctx->pathSpec + ); + fill_and_display_if_required(line1, pathStr, getPublicKeys_respondOneKey_ui_runStep, respond_with_user_reject); +} +#endif // HAVE_NBGL + +void getPublicKeys_respondOneKey_ui_runStep() +{ + TRACE("UI step %d", ctx->ui_step); + ui_callback_fn_t* this_fn = getPublicKeys_respondOneKey_ui_runStep; + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + UI_STEP(GET_KEY_UI_STEP_WARNING) { +#ifdef HAVE_BAGL + ui_displayPaginatedText( + "Unusual request", + "Proceed with care", + this_fn + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning( + "Unusual request", + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } + UI_STEP(GET_KEY_UI_STEP_PROMPT) { +#ifdef HAVE_BAGL + UI_STEP_JUMP(GET_KEY_UI_STEP_DISPLAY) +#elif defined(HAVE_NBGL) + display_prompt( + "Export public key", + "", + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } + UI_STEP(GET_KEY_UI_STEP_DISPLAY) { +#ifdef HAVE_BAGL + ui_displayGetPublicKeyPathScreen(&ctx->pathSpec, this_fn); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + bool showAccountDescription = (bip44_classifyPath(&ctx->pathSpec) == PATH_ORDINARY_ACCOUNT); + if (showAccountDescription) { + char line1[30]; + char line2[30]; + ui_getAccountScreeen( + line1, + SIZEOF(line1), + line2, + SIZEOF(line2), + &ctx->pathSpec + ); + fill_and_display_if_required(line1, line2, getPublicKeys_respondOneKey_ui_cb, respond_with_user_reject); + } + else { + getPublicKeys_respondOneKey_ui_cb(); + } +#endif // HAVE_BAGL + } + UI_STEP(GET_KEY_UI_STEP_CONFIRM) { +#ifdef HAVE_BAGL + ui_displayPrompt( + "Confirm export", + "public key?", + this_fn, + respond_with_user_reject + ); +#elif defined(HAVE_NBGL) + display_confirmation( + "Confirm\npublic key export", + "", + "PUBLIC KEY\nEXPORTED", + "Public key\nrejected", + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } + UI_STEP(GET_KEY_UI_STEP_RESPOND) { + ASSERT(ctx->responseReadyMagic == RESPONSE_READY_MAGIC); + + io_send_buf(SUCCESS, (uint8_t*) &ctx->extPubKey, SIZEOF(ctx->extPubKey)); + ctx->responseReadyMagic = 0; // just for safety +#ifdef HAVE_BAGL + ui_displayBusy(); // needs to happen after I/O +#endif // HAVE_BAGL + + ctx->currentPath++; + TRACE("Current path: %u / %u", ctx->currentPath, ctx->numPaths); + + if (ctx->currentPath == 1 || ctx->currentPath == ctx->numPaths) + advanceStage(); + } + UI_STEP_END(UI_STEP_NONE); +} + +// ============================== INIT ============================== + +void getPublicKeys_handleInit_ui_runStep() +{ + TRACE("UI step %d", ctx->ui_step); + ui_callback_fn_t* this_fn = getPublicKeys_handleInit_ui_runStep; + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + UI_STEP(HANDLE_INIT_UI_STEP_CONFIRM) { + char secondLine[100] = {0}; + explicit_bzero(secondLine, SIZEOF(secondLine)); + STATIC_ASSERT(sizeof(ctx->numPaths) <= sizeof(unsigned), "oversized type for %u"); + STATIC_ASSERT(!IS_SIGNED(ctx->numPaths), "signed type for %u"); + snprintf(secondLine, SIZEOF(secondLine), "%u public keys?", ctx->numPaths); + // make sure all the information is displayed to the user + ASSERT(strlen(secondLine) + 1 < SIZEOF(secondLine)); + +#ifdef HAVE_BAGL + ui_displayPrompt( + "Confirm export", + secondLine, + this_fn, + respond_with_user_reject + ); + +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt( + "Review export", + secondLine, + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_INIT_UI_STEP_RESPOND) { + ctx->ui_step = UI_STEP_NONE; // we are finished with this UI state machine + + runGetOnePublicKeyUIFlow(); // run another UI state machine + + // This return statement is needed to bail out from this UI state machine + // which would otherwise be in conflict with the (async) UI state + // machine triggered by promptAndRespondOneKey. + + // Those two machines share the ctx->ui_state variable. + // Without the return statement, UI_STEP_END would overwrite it. + + // WARNING: This works under the assumption that HANDLE_INIT_UI_STEP_RESPOND + // is a terminal state of this UI state machine! + return; + } + UI_STEP_END(UI_STEP_NONE); +} diff --git a/src/getPublicKeys_ui.h b/src/getPublicKeys_ui.h new file mode 100644 index 00000000..2132a382 --- /dev/null +++ b/src/getPublicKeys_ui.h @@ -0,0 +1,24 @@ +#ifndef H_CARDANO_APP_GET_PUBLIC_KEYS_UI +#define H_CARDANO_APP_GET_PUBLIC_KEYS_UI + +// ============================== derivation and UI state machine for one key ============================== + +enum { + GET_KEY_UI_STEP_WARNING = 200, + GET_KEY_UI_STEP_PROMPT, + GET_KEY_UI_STEP_DISPLAY, + GET_KEY_UI_STEP_CONFIRM, + GET_KEY_UI_STEP_RESPOND, +} ; + +void getPublicKeys_respondOneKey_ui_runStep(); + +// ============================== INIT ============================== + +enum { + HANDLE_INIT_UI_STEP_CONFIRM = 100, + HANDLE_INIT_UI_STEP_RESPOND, // WARNING: this must be the last valid step, see below +} ; + +void getPublicKeys_handleInit_ui_runStep(); +#endif // H_CARDANO_APP_GET_PUBLIC_KEYS_UI From deebb2c0ff101791ae8a74800dd60372353d03d7 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 19 Oct 2022 11:22:43 +0200 Subject: [PATCH 017/105] signOpCert: update for stax --- src/signOpCert.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/src/signOpCert.c b/src/signOpCert.c index 65f0ae27..5ac2e9be 100644 --- a/src/signOpCert.c +++ b/src/signOpCert.c @@ -5,11 +5,16 @@ #include "endian.h" #include "state.h" #include "uiHelpers.h" -#include "uiScreens.h" #include "securityPolicy.h" #include "messageSigning.h" #include "textUtils.h" +#ifdef HAVE_BAGL +#include "uiScreens_bagl.h" +#elif defined(HAVE_NBGL) +#include "uiScreens_nbgl.h" +#endif + static ins_sign_op_cert_context_t* ctx = &(instructionState.signOpCertContext); @@ -130,69 +135,116 @@ static void signOpCert_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(UI_STEP_WARNING) { +#ifdef HAVE_BAGL ui_displayPaginatedText( "Unusual request", "Proceed with care", this_fn ); +#elif defined(HAVE_NBGL) + display_warning( + "Unusual request", + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL } UI_STEP(UI_STEP_CONFIRM_START) { +#ifdef HAVE_BAGL ui_displayPrompt( "Start new", "operational certificate?", this_fn, respond_with_user_reject ); +#elif defined(HAVE_NBGL) + display_prompt( + "Start new\noperational certificate", + "", + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL } UI_STEP(UI_STEP_DISPLAY_POOL_COLD_KEY_PATH) { +#ifdef HAVE_BAGL ui_displayPathScreen("Pool cold key path", &ctx->poolColdKeyPathSpec, this_fn); +#elif defined(HAVE_NBGL) + char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; + ui_getPathScreen(pathStr, SIZEOF(pathStr), &ctx->poolColdKeyPathSpec); + fill_and_display_if_required("Pool cold key path", pathStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL } UI_STEP(UI_STEP_DISPLAY_POOL_ID) { uint8_t poolKeyHash[POOL_KEY_HASH_LENGTH] = {0}; bip44_pathToKeyHash(&ctx->poolColdKeyPathSpec, poolKeyHash, SIZEOF(poolKeyHash)); +#ifdef HAVE_BAGL ui_displayBech32Screen( "Pool ID", "pool", poolKeyHash, SIZEOF(poolKeyHash), this_fn ); +#elif defined(HAVE_NBGL) + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "pool", poolKeyHash, SIZEOF(poolKeyHash)); + fill_and_display_if_required("Pool ID", encodedStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL } UI_STEP(UI_STEP_DISPLAY_KES_PUBLIC_KEY) { +#ifdef HAVE_BAGL ui_displayBech32Screen( "KES public key", "kes_vk", ctx->kesPublicKey, SIZEOF(ctx->kesPublicKey), this_fn ); +#elif defined(HAVE_NBGL) + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "kes_vk", ctx->kesPublicKey, SIZEOF(ctx->kesPublicKey)); + fill_and_display_if_required("KES public key", encodedStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL } UI_STEP(UI_STEP_DISPLAY_KES_PERIOD) { char kesPeriodString[50] = {0}; explicit_bzero(kesPeriodString, SIZEOF(kesPeriodString)); str_formatUint64(ctx->kesPeriod, kesPeriodString, SIZEOF(kesPeriodString)); +#ifdef HAVE_BAGL ui_displayPaginatedText( "KES period", kesPeriodString, this_fn ); +#elif defined(HAVE_NBGL) + fill_and_display_if_required("KES period", kesPeriodString, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL } UI_STEP(UI_STEP_DISPLAY_ISSUE_COUNTER) { char issueCounterString[50] = {0}; explicit_bzero(issueCounterString, SIZEOF(issueCounterString)); str_formatUint64(ctx->issueCounter, issueCounterString, SIZEOF(issueCounterString)); +#ifdef HAVE_BAGL ui_displayPaginatedText( "Issue counter", issueCounterString, this_fn ); +#elif defined(HAVE_NBGL) + fill_and_display_if_required("Issue counter", issueCounterString, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL } UI_STEP(UI_STEP_CONFIRM) { +#ifdef HAVE_BAGL ui_displayPrompt( "Confirm", "operational certificate?", this_fn, respond_with_user_reject ); +#elif defined(HAVE_NBGL) + display_confirmation("Confirm\n operation certificate", "", "OP CERTIFICATE\nCONFIRMED", "Op certificate\nrejected", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL } UI_STEP(UI_STEP_RESPOND) { ASSERT(ctx->responseReadyMagic == RESPONSE_READY_MAGIC); From 492ed0aa92aa5db19f2961d60b84e1f463c70aa2 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 19 Oct 2022 11:42:16 +0200 Subject: [PATCH 018/105] deriveAddress: update for stax --- src/deriveAddress.c | 114 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 1 deletion(-) diff --git a/src/deriveAddress.c b/src/deriveAddress.c index 3ab19732..24f3ead0 100644 --- a/src/deriveAddress.c +++ b/src/deriveAddress.c @@ -2,13 +2,18 @@ #include "state.h" #include "securityPolicy.h" #include "uiHelpers.h" -#include "uiScreens.h" #include "addressUtilsByron.h" #include "addressUtilsShelley.h" #include "base58.h" #include "bech32.h" #include "bufView.h" +#ifdef HAVE_BAGL +#include "uiScreens_bagl.h" +#elif defined(HAVE_NBGL) +#include "uiScreens_nbgl.h" +#endif + static uint16_t RESPONSE_READY_MAGIC = 11223; static ins_derive_address_context_t* ctx = &(instructionState.deriveAddressContext); @@ -18,6 +23,14 @@ enum { P1_DISPLAY = 0x02, }; + +void deriveAddress_response(void) { + ctx->responseReadyMagic = 0; + ASSERT(ctx->address.size <= SIZEOF(ctx->address.buffer)); + + io_send_buf(SUCCESS, ctx->address.buffer, ctx->address.size); + ui_idle(); +} static void prepareResponse() { ctx->address.size = deriveAddress( @@ -69,32 +82,77 @@ static void deriveAddress_return_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(RETURN_UI_STEP_WARNING) { +#ifdef HAVE_BAGL ui_displayPaginatedText( "Unusual request", "Proceed with care", this_fn ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning( + "Unusual request", + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL } UI_STEP(RETURN_UI_STEP_BEGIN) { +#ifdef HAVE_BAGL ui_displayPaginatedText("Export", "address", this_fn); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt( + "Export address", + "", + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL } UI_STEP(RETURN_UI_STEP_SPENDING_PATH) { if (determineSpendingChoice(ctx->addressParams.type) == SPENDING_NONE) { // reward address UI_STEP_JUMP(RETURN_UI_STEP_STAKING_INFO); } +#ifdef HAVE_BAGL ui_displaySpendingInfoScreen(&ctx->addressParams, this_fn); +#elif defined(HAVE_NBGL) +#define SPENDING_INFO_SIZE MAX(11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX, 2 * BECH32_BUFFER_SIZE_MAX) + char line1[30]; + char spendingInfo[SPENDING_INFO_SIZE] = {0}; + ui_getSpendingInfoScreen(line1, SIZEOF(line1), spendingInfo, SIZEOF(spendingInfo), &ctx->addressParams); + fill_and_display_if_required(line1, spendingInfo, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL } UI_STEP(RETURN_UI_STEP_STAKING_INFO) { +#ifdef HAVE_BAGL ui_displayStakingInfoScreen(&ctx->addressParams, this_fn); +#elif defined(HAVE_NBGL) + char line1[30] = {0}; + char stakingInfo[120] = {0}; + ui_getStakingInfoScreen(line1, SIZEOF(line1), stakingInfo, SIZEOF(stakingInfo), &ctx->addressParams); + fill_and_display_if_required(line1, stakingInfo, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL } UI_STEP(RETURN_UI_STEP_CONFIRM) { +#ifdef HAVE_BAGL ui_displayPrompt( "Confirm", "export address?", this_fn, respond_with_user_reject ); +#elif defined(HAVE_NBGL) + display_confirmation( + "Confirm\n address export", + "", + "ADDRESS\nEXPORTED", + "Address\nrejected", + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL } UI_STEP(RETURN_UI_STEP_RESPOND) { ctx->responseReadyMagic = 0; @@ -148,44 +206,98 @@ static void deriveAddress_display_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(DISPLAY_UI_STEP_WARNING) { +#ifdef HAVE_BAGL ui_displayPaginatedText( "Unusual request", "Proceed with care", this_fn ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning( + "Unusual request", + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL } UI_STEP(DISPLAY_UI_STEP_INSTRUCTIONS) { +#ifdef HAVE_BAGL ui_displayPaginatedText( "Verify address", "Make sure it agrees with your computer", this_fn ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning( + "Make sure address matches\nwith your computer", + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL } UI_STEP(DISPLAY_UI_STEP_SPENDING_INFO) { if (determineSpendingChoice(ctx->addressParams.type) == SPENDING_NONE) { // reward address UI_STEP_JUMP(DISPLAY_UI_STEP_STAKING_INFO); } +#ifdef HAVE_BAGL ui_displaySpendingInfoScreen(&ctx->addressParams, this_fn); +#elif defined(HAVE_NBGL) +#define SPENDING_INFO_SIZE MAX(11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX, 2 * BECH32_BUFFER_SIZE_MAX) + char line1[30] = {0}; + char spendingInfo[SPENDING_INFO_SIZE] = {0}; + ui_getSpendingInfoScreen(line1, SIZEOF(line1), spendingInfo, SIZEOF(spendingInfo), &ctx->addressParams); + fill_address_data(line1, spendingInfo); + UI_STEP_JUMP(DISPLAY_UI_STEP_STAKING_INFO); +#endif // HAVE_BAGL } UI_STEP(DISPLAY_UI_STEP_STAKING_INFO) { +#ifdef HAVE_BAGL ui_displayStakingInfoScreen(&ctx->addressParams, this_fn); +#elif defined(HAVE_NBGL) + char line1[30] = {0}; + char stakingInfo[120] = {0}; + ui_getStakingInfoScreen(line1, SIZEOF(line1), stakingInfo, SIZEOF(stakingInfo), &ctx->addressParams); + fill_address_data(line1, stakingInfo); + UI_STEP_JUMP(DISPLAY_UI_STEP_ADDRESS); +#endif // HAVE_BAGL } UI_STEP(DISPLAY_UI_STEP_ADDRESS) { ASSERT(ctx->address.size <= SIZEOF(ctx->address.buffer)); +#ifdef HAVE_BAGL ui_displayAddressScreen( "Address", ctx->address.buffer, ctx->address.size, this_fn ); +#elif defined(HAVE_NBGL) + char humanAddress[MAX_HUMAN_ADDRESS_SIZE] = {0}; + ui_getAddressScreen( + humanAddress, + SIZEOF(humanAddress), + ctx->address.buffer, + ctx->address.size + ); + fill_address_data((char*)"Address", humanAddress); + UI_STEP_JUMP(DISPLAY_UI_STEP_CONFIRM) +#endif // HAVE_BAGL } UI_STEP(DISPLAY_UI_STEP_CONFIRM) { +#ifdef HAVE_BAGL ui_displayPrompt( "Confirm", "address?", this_fn, respond_with_user_reject ); +#elif defined(HAVE_NBGL) + display_address( + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL } UI_STEP(DISPLAY_UI_STEP_RESPOND) { io_send_buf(SUCCESS, NULL, 0); From c9294132b9e8051fa1e97c0361943fb8bcc39725 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 19 Oct 2022 18:56:19 +0200 Subject: [PATCH 019/105] deriveNativeScriptHash: update for stax --- src/deriveNativeScriptHash.c | 206 +------------------ src/deriveNativeScriptHash_ui.c | 337 ++++++++++++++++++++++++++++++++ src/deriveNativeScriptHash_ui.h | 21 ++ 3 files changed, 365 insertions(+), 199 deletions(-) create mode 100644 src/deriveNativeScriptHash_ui.c create mode 100644 src/deriveNativeScriptHash_ui.h diff --git a/src/deriveNativeScriptHash.c b/src/deriveNativeScriptHash.c index 2ef7ec08..cac061f9 100644 --- a/src/deriveNativeScriptHash.c +++ b/src/deriveNativeScriptHash.c @@ -1,7 +1,13 @@ #include "deriveNativeScriptHash.h" +#include "deriveNativeScriptHash_ui.h" #include "state.h" #include "textUtils.h" -#include "uiScreens.h" + +#ifdef HAVE_BAGL +#include "uiScreens_bagl.h" +#elif defined(HAVE_NBGL) +#include "uiScreens_nbgl.h" +#endif static ins_derive_native_script_hash_context_t* ctx = &(instructionState.deriveNativeScriptHashContext); @@ -48,177 +54,6 @@ static inline void simpleScriptFinished() } // UI -typedef const char* charPtr; -const charPtr ui_native_script_header[7] = {"Script - key path", "Script - key", "Script - ALL", "Script - ANY", "Script - N of K", "Script - invalid before", "Script - invalid hereafter"}; - -#define ASSERT_UI_SCRIPT_TYPE_SANITY() ASSERT(ctx->ui_scriptType >= UI_SCRIPT_PUBKEY_PATH && ctx->ui_scriptType <= UI_SCRIPT_INVALID_HEREAFTER) -#define HEADER ((const char*)PIC(ui_native_script_header[ctx->ui_scriptType])) - -static uint8_t _getScriptLevelForPosition() -{ - // For complex scripts we reduce the current level by 1 - // Because they already have the level increased by 1 - uint8_t levelOffset = ctx->ui_scriptType == UI_SCRIPT_ALL - || ctx->ui_scriptType == UI_SCRIPT_ANY - || ctx->ui_scriptType == UI_SCRIPT_N_OF_K - ? 1 : 0; - ASSERT(levelOffset == 0 || ctx->level > 0); - return ctx->level - levelOffset; -} - -static void deriveScriptHash_display_ui_position(uint8_t level, ui_callback_fn_t* callback) -{ - ASSERT_UI_SCRIPT_TYPE_SANITY(); - ASSERT(level > 0); - TRACE(); - - // 10 - length of the leading prefix: "Position: " - // 11 - max length for the position information for one level: "x." - // where x is 2^32-1 - // 2 - the ending null byte + 1B for checking if all text has been printed - char positionDescription[10 + 11 * (MAX_SCRIPT_DEPTH - 1) + 2] = {0}; - explicit_bzero(positionDescription, SIZEOF(positionDescription)); - char* ptr = BEGIN(positionDescription); - char* end = END(positionDescription); - - snprintf(ptr, (end - ptr), "Position: "); - // snprintf returns 0, https://github.com/LedgerHQ/nanos-secure-sdk/issues/28 - // so we need to check the number of written characters by `strlen` - ptr += strlen(ptr); - - for (size_t i = 1; i <= level; i++) { - ASSERT(i < MAX_SCRIPT_DEPTH); - uint32_t position = ctx->complexScripts[i].totalScripts - ctx->complexScripts[i].remainingScripts + 1; - STATIC_ASSERT(sizeof(position) <= sizeof(unsigned), "oversized type for %u"); - STATIC_ASSERT(!IS_SIGNED(position), "signed type for %u"); - snprintf(ptr, (end - ptr), "%u.", position); - ASSERT(strlen(positionDescription) + 1 < SIZEOF(positionDescription)); - ptr += strlen(ptr); - } - - // remove any trailing '.' - ASSERT(ptr > BEGIN(positionDescription)); - *(ptr - 1) = '\0'; - - ASSERT(strlen(positionDescription) + 1 < SIZEOF(positionDescription)); - - VALIDATE(uiPaginatedText_canFitStringIntoFullText(positionDescription), ERR_INVALID_DATA); - - ui_displayPaginatedText( - HEADER, - positionDescription, - callback - ); -} - -enum { - DISPLAY_UI_STEP_POSITION = 200, - DISPLAY_UI_STEP_SCRIPT_CONTENT, - DISPLAY_UI_STEP_RESPOND, - DISPLAY_UI_STEP_INVALID -}; - -static void deriveScriptHash_display_ui_runStep() -{ - TRACE("ui_step = %d", ctx->ui_step); - ASSERT_UI_SCRIPT_TYPE_SANITY(); - - ui_callback_fn_t* this_fn = deriveScriptHash_display_ui_runStep; - UI_STEP_BEGIN(ctx->ui_step, this_fn); - - UI_STEP(DISPLAY_UI_STEP_POSITION) { - uint8_t level = _getScriptLevelForPosition(); - if (level == 0) { - TRACE("Skip showing position"); - UI_STEP_JUMP(DISPLAY_UI_STEP_SCRIPT_CONTENT); - } - deriveScriptHash_display_ui_position(level, this_fn); - } - - UI_STEP(DISPLAY_UI_STEP_SCRIPT_CONTENT) { - TRACE("ui_scriptType = %d", ctx->ui_scriptType); - switch (ctx->ui_scriptType) { - case UI_SCRIPT_PUBKEY_PATH: { - ui_displayPathScreen( - HEADER, - &ctx->scriptContent.pubkeyPath, - this_fn - ); - break; - } - case UI_SCRIPT_PUBKEY_HASH: { - ui_displayBech32Screen( - HEADER, - "addr_shared_vkh", - ctx->scriptContent.pubkeyHash, - ADDRESS_KEY_HASH_LENGTH, - this_fn - ); - break; - } - case UI_SCRIPT_ALL: - case UI_SCRIPT_ANY: { - // max possible length 35: "Contains n nested scripts." - // where n is 2^32-1 - char text[37] = {0}; - explicit_bzero(text, SIZEOF(text)); - STATIC_ASSERT(sizeof(ctx->complexScripts[ctx->level].remainingScripts) <= sizeof(unsigned), "oversized type for %u"); - STATIC_ASSERT(!IS_SIGNED(ctx->complexScripts[ctx->level].remainingScripts), "signed type for %u"); - snprintf(text, SIZEOF(text), "Contains %u nested scripts.", ctx->complexScripts[ctx->level].remainingScripts); - // make sure all the information is displayed to the user - ASSERT(strlen(text) + 1 < SIZEOF(text)); - - ui_displayPaginatedText( - HEADER, - text, - this_fn - ); - break; - } - case UI_SCRIPT_N_OF_K: { - // max possible length 85: "Requires n out of k signatures. Contains k nested scripts." - // where n and k is 2^32-1 - char text[87] = {0}; - explicit_bzero(text, SIZEOF(text)); - STATIC_ASSERT(sizeof(ctx->scriptContent.requiredScripts) <= sizeof(unsigned), "oversized type for %u"); - STATIC_ASSERT(!IS_SIGNED(ctx->scriptContent.requiredScripts), "signed type for %u"); - STATIC_ASSERT(sizeof(ctx->complexScripts[ctx->level].remainingScripts) <= sizeof(unsigned), "oversized type for %u"); - STATIC_ASSERT(!IS_SIGNED(ctx->complexScripts[ctx->level].remainingScripts), "signed type for %u"); - snprintf(text, SIZEOF(text), "Requires %u out of %u signatures. Contains %u nested scripts", ctx->scriptContent.requiredScripts, ctx->complexScripts[ctx->level].remainingScripts, ctx->complexScripts[ctx->level].remainingScripts); - // make sure all the information is displayed to the user - ASSERT(strlen(text) + 1 < SIZEOF(text)); - - ui_displayPaginatedText( - HEADER, - text, - this_fn - ); - break; - } - case UI_SCRIPT_INVALID_BEFORE: - case UI_SCRIPT_INVALID_HEREAFTER: { - ui_displayUint64Screen( - HEADER, - ctx->scriptContent.timelock, - this_fn - ); - break; - } - default: - THROW(ERR_INVALID_STATE); - } - } - - UI_STEP(DISPLAY_UI_STEP_RESPOND) { - io_send_buf(SUCCESS, NULL, 0); - ui_displayBusy(); // displays dots, called only after I/O to avoid freezing - } - - UI_STEP_END(DISPLAY_UI_STEP_INVALID); -} -#undef HEADER -#undef ASSERT_UI_SCRIPT_TYPE_SANITY - #define UI_DISPLAY_SCRIPT(UI_TYPE) {\ ctx->ui_scriptType = UI_TYPE;\ ctx->ui_step = DISPLAY_UI_STEP_POSITION;\ @@ -399,33 +234,6 @@ typedef enum { DISPLAY_NATIVE_SCRIPT_HASH_POLICY_ID = 2, } display_format; -static void deriveNativeScriptHash_displayNativeScriptHash_callback() -{ - io_send_buf(SUCCESS, ctx->scriptHashBuffer, SCRIPT_HASH_LENGTH); - ui_idle(); -} - -static void deriveNativeScriptHash_displayNativeScriptHash_bech32() -{ - ui_displayBech32Screen( - "Script hash", - "script", - ctx->scriptHashBuffer, - SCRIPT_HASH_LENGTH, - deriveNativeScriptHash_displayNativeScriptHash_callback - ); -} - -static void deriveNativeScriptHash_displayNativeScriptHash_policyId() -{ - ui_displayHexBufferScreen( - "Policy ID", - ctx->scriptHashBuffer, - SCRIPT_HASH_LENGTH, - deriveNativeScriptHash_displayNativeScriptHash_callback - ); -} - static void deriveNativeScriptHash_handleWholeNativeScriptFinish(read_view_t* view) { // we finish only if there are no more scripts to be processed diff --git a/src/deriveNativeScriptHash_ui.c b/src/deriveNativeScriptHash_ui.c new file mode 100644 index 00000000..295c0ccb --- /dev/null +++ b/src/deriveNativeScriptHash_ui.c @@ -0,0 +1,337 @@ +#include "deriveNativeScriptHash.h" +#include "deriveNativeScriptHash_ui.h" +#include "state.h" +#include "textUtils.h" + +#ifdef HAVE_BAGL +#include "uiScreens_bagl.h" +#elif defined(HAVE_NBGL) +#include "uiScreens_nbgl.h" +#include "nbgl_use_case.h" +#endif + +static ins_derive_native_script_hash_context_t* ctx = &(instructionState.deriveNativeScriptHashContext); + +// UI +typedef char* charPtr; +const charPtr ui_native_script_header[7] = {"Script - key path", "Script - key", "Script - ALL", "Script - ANY", "Script - N of K", "Script - invalid before", "Script - invalid hereafter"}; + +#define ASSERT_UI_SCRIPT_TYPE_SANITY() ASSERT(ctx->ui_scriptType >= UI_SCRIPT_PUBKEY_PATH && ctx->ui_scriptType <= UI_SCRIPT_INVALID_HEREAFTER) +#define HEADER ((const char*)PIC(ui_native_script_header[ctx->ui_scriptType])) + +static uint8_t _getScriptLevelForPosition() +{ + // For complex scripts we reduce the current level by 1 + // Because they already have the level increased by 1 + uint8_t levelOffset = ctx->ui_scriptType == UI_SCRIPT_ALL + || ctx->ui_scriptType == UI_SCRIPT_ANY + || ctx->ui_scriptType == UI_SCRIPT_N_OF_K + ? 1 : 0; + ASSERT(levelOffset == 0 || ctx->level > 0); + return ctx->level - levelOffset; +} + +static void deriveScriptHash_display_ui_position(uint8_t level, ui_callback_fn_t* callback) +{ + ASSERT_UI_SCRIPT_TYPE_SANITY(); + ASSERT(level > 0); + TRACE(); + + // 10 - length of the leading prefix: "Position: " + // 11 - max length for the position information for one level: "x." + // where x is 2^32-1 + // 2 - the ending null byte + 1B for checking if all text has been printed + char positionDescription[10 + 11 * (MAX_SCRIPT_DEPTH - 1) + 2] = {0}; + explicit_bzero(positionDescription, SIZEOF(positionDescription)); + char* ptr = BEGIN(positionDescription); + char* end = END(positionDescription); + + snprintf(ptr, (end - ptr), "Position: "); + // snprintf returns 0, https://github.com/LedgerHQ/nanos-secure-sdk/issues/28 + // so we need to check the number of written characters by `strlen` + ptr += strlen(ptr); + + for (size_t i = 1; i <= level; i++) { + ASSERT(i < MAX_SCRIPT_DEPTH); + uint32_t position = ctx->complexScripts[i].totalScripts - ctx->complexScripts[i].remainingScripts + 1; + STATIC_ASSERT(sizeof(position) <= sizeof(unsigned), "oversized type for %u"); + STATIC_ASSERT(!IS_SIGNED(position), "signed type for %u"); + snprintf(ptr, (end - ptr), "%u.", position); + ASSERT(strlen(positionDescription) + 1 < SIZEOF(positionDescription)); + ptr += strlen(ptr); + } + + // remove any trailing '.' + ASSERT(ptr > BEGIN(positionDescription)); + *(ptr - 1) = '\0'; + + ASSERT(strlen(positionDescription) + 1 < SIZEOF(positionDescription)); + + VALIDATE(uiPaginatedText_canFitStringIntoFullText(positionDescription), ERR_INVALID_DATA); + +#ifdef HAVE_BAGL + ui_displayPaginatedText( + HEADER, + positionDescription, + callback + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + fill_and_display_new_page(HEADER, positionDescription, callback, respond_with_user_reject); +#endif // HAVE_BAGL +} + +#ifdef HAVE_NBGL +static void deriveScriptHash_display_ui_runStep_cb(void) { + // max possible length 85: "Requires n out of k signatures. Contains k nested scripts." + // where n and k is 2^32-1 + char text[87] = {0}; + explicit_bzero(text, SIZEOF(text)); + snprintf(text, SIZEOF(text), "%u nested scripts", ctx->complexScripts[ctx->level].remainingScripts); + // make sure all the information is displayed to the user + ASSERT(strlen(text) + 1 < SIZEOF(text)); + fill_and_display_if_required("Script contents", text, deriveScriptHash_display_ui_runStep, respond_with_user_reject); +} +#endif // HAVE_NBGL + +void deriveScriptHash_display_ui_runStep() +{ + TRACE("ui_step = %d", ctx->ui_step); + ASSERT_UI_SCRIPT_TYPE_SANITY(); + + ui_callback_fn_t* this_fn = deriveScriptHash_display_ui_runStep; + UI_STEP_BEGIN(ctx->ui_step, this_fn); + + UI_STEP(DISPLAY_UI_STEP_POSITION) { + uint8_t level = _getScriptLevelForPosition(); + if (level == 0) { + TRACE("Skip showing position"); + UI_STEP_JUMP(DISPLAY_UI_STEP_SCRIPT_CONTENT); + } + else { + deriveScriptHash_display_ui_position(level, this_fn); + } + } + + UI_STEP(DISPLAY_UI_STEP_TITLE) { +#ifdef HAVE_BAGL + UI_STEP_JUMP(DISPLAY_UI_STEP_SCRIPT_CONTENT); +#elif defined(HAVE_NBGL) + display_prompt("Review Script", "", this_fn, respond_with_user_reject); +#endif // HAVE_NBGL + } +#ifdef HAVE_NBGL + UI_STEP(DISPLAY_UI_STEP_SCRIPT_TYPE) { + set_light_confirmation(true); + switch (ctx->ui_scriptType) { + case UI_SCRIPT_PUBKEY_PATH: + fill_and_display_if_required("Script type", "Pubkey path", this_fn, respond_with_user_reject); + break; + case UI_SCRIPT_PUBKEY_HASH: + fill_and_display_if_required("Script type", "Pubkey hash", this_fn, respond_with_user_reject); + break; + case UI_SCRIPT_ALL: + fill_and_display_if_required("Script type", "ALL", this_fn, respond_with_user_reject); + break; + case UI_SCRIPT_ANY: + fill_and_display_if_required("Script type", "ANY", this_fn, respond_with_user_reject); + break; + case UI_SCRIPT_N_OF_K: + fill_and_display_if_required("Script type", "N out K", this_fn, respond_with_user_reject); + break; + case UI_SCRIPT_INVALID_BEFORE: + fill_and_display_if_required("Script type", "Invalid before", this_fn, respond_with_user_reject); + break; + case UI_SCRIPT_INVALID_HEREAFTER: + fill_and_display_if_required("Script type", "Invalid hereafter", this_fn, respond_with_user_reject); + break; + default: + THROW(ERR_INVALID_STATE); + } + } +#endif // HAVE_NBGL + + UI_STEP(DISPLAY_UI_STEP_SCRIPT_CONTENT) { + TRACE("ui_scriptType = %d", ctx->ui_scriptType); + switch (ctx->ui_scriptType) { + case UI_SCRIPT_PUBKEY_PATH: { +#ifdef HAVE_BAGL + ui_displayPathScreen( + HEADER, + &ctx->scriptContent.pubkeyPath, + this_fn + ); +#elif defined(HAVE_NBGL) + char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; + ui_getPathScreen(pathStr, SIZEOF(pathStr), &ctx->scriptContent.pubkeyPath); + fill_and_display_if_required("Pubkey path", pathStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + break; + } + case UI_SCRIPT_PUBKEY_HASH: { +#ifdef HAVE_BAGL + ui_displayBech32Screen( + HEADER, + "addr_shared_vkh", + ctx->scriptContent.pubkeyHash, + ADDRESS_KEY_HASH_LENGTH, + this_fn + ); +#elif defined(HAVE_NBGL) + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "addr_shared_vkh", ctx->scriptContent.pubkeyHash, ADDRESS_KEY_HASH_LENGTH); + fill_and_display_if_required("Pubkey hash", encodedStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + break; + } + case UI_SCRIPT_ALL: + case UI_SCRIPT_ANY: { + // max possible length 35: "Contains n nested scripts." + // where n is 2^32-1 + char text[37] = {0}; + explicit_bzero(text, SIZEOF(text)); + STATIC_ASSERT(sizeof(ctx->complexScripts[ctx->level].remainingScripts) <= sizeof(unsigned), "oversized type for %u"); + STATIC_ASSERT(!IS_SIGNED(ctx->complexScripts[ctx->level].remainingScripts), "signed type for %u"); +#ifdef HAVE_BAGL + snprintf(text, SIZEOF(text), "Contains %u nested scripts.", ctx->complexScripts[ctx->level].remainingScripts); + // make sure all the information is displayed to the user + ASSERT(strlen(text) + 1 < SIZEOF(text)); + + ui_displayPaginatedText( + HEADER, + text, + this_fn + ); +#elif defined(HAVE_NBGL) + snprintf(text, SIZEOF(text), "%u nested scripts", ctx->complexScripts[ctx->level].remainingScripts); + // make sure all the information is displayed to the user + ASSERT(strlen(text) + 1 < SIZEOF(text)); + fill_and_display_if_required("Content", text, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + break; + } + case UI_SCRIPT_N_OF_K: { + STATIC_ASSERT(sizeof(ctx->scriptContent.requiredScripts) <= sizeof(unsigned), "oversized type for %u"); + STATIC_ASSERT(!IS_SIGNED(ctx->scriptContent.requiredScripts), "signed type for %u"); + STATIC_ASSERT(sizeof(ctx->complexScripts[ctx->level].remainingScripts) <= sizeof(unsigned), "oversized type for %u"); + STATIC_ASSERT(!IS_SIGNED(ctx->complexScripts[ctx->level].remainingScripts), "signed type for %u"); + // max possible length 85: "Requires n out of k signatures. Contains k nested scripts." + // where n and k is 2^32-1 + char text[87] = {0}; +#ifdef HAVE_BAGL + explicit_bzero(text, SIZEOF(text)); + snprintf(text, SIZEOF(text), "Requires %u out of %u signatures. Contains %u nested scripts", ctx->scriptContent.requiredScripts, ctx->complexScripts[ctx->level].remainingScripts, ctx->complexScripts[ctx->level].remainingScripts); + // make sure all the information is displayed to the user + ASSERT(strlen(text) + 1 < SIZEOF(text)); + + ui_displayPaginatedText( + HEADER, + text, + this_fn + ); +#elif defined(HAVE_NBGL) + explicit_bzero(text, SIZEOF(text)); + snprintf(text, SIZEOF(text), "%u out of %u signatures", ctx->scriptContent.requiredScripts, ctx->complexScripts[ctx->level].remainingScripts); + // make sure all the information is displayed to the user + ASSERT(strlen(text) + 1 < SIZEOF(text)); + fill_and_display_if_required("Requirement", text, deriveScriptHash_display_ui_runStep_cb, respond_with_user_reject); +#endif // HAVE_BAGL + break; + } + case UI_SCRIPT_INVALID_BEFORE: { +#ifdef HAVE_BAGL + ui_displayUint64Screen( + HEADER, + ctx->scriptContent.timelock, + this_fn + ); +#elif defined(HAVE_NBGL) + char line[30]; + ui_getUint64Screen( + line, + SIZEOF(line), + ctx->scriptContent.timelock + ); + fill_and_display_if_required("Invalid before", line, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + break; + } + + case UI_SCRIPT_INVALID_HEREAFTER: { +#ifdef HAVE_BAGL + ui_displayUint64Screen( + HEADER, + ctx->scriptContent.timelock, + this_fn + ); +#elif defined(HAVE_NBGL) + char line[30]; + ui_getUint64Screen( + line, + SIZEOF(line), + ctx->scriptContent.timelock + ); + fill_and_display_if_required("Invalid hereafter", line, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + break; + } + default: + THROW(ERR_INVALID_STATE); + } + } + + UI_STEP(DISPLAY_UI_STEP_RESPOND) { + io_send_buf(SUCCESS, NULL, 0); +#ifdef HAVE_BAGL + ui_displayBusy(); // displays dots, called only after I/O to avoid freezing +#endif // HAVE_BAGL + } + + UI_STEP_END(DISPLAY_UI_STEP_INVALID); +} +// Whole native script finish + +void deriveNativeScriptHash_displayNativeScriptHash_callback() +{ + io_send_buf(SUCCESS, ctx->scriptHashBuffer, SCRIPT_HASH_LENGTH); + ui_idle(); +} + +#ifdef HAVE_NBGL +static void deriveNativeScriptHash_displayNativeScriptHash_finish(void) { + display_confirmation("Confirm script", "", "SCRIPT\nCONFIRMED", "Script\nrejected", deriveNativeScriptHash_displayNativeScriptHash_callback, respond_with_user_reject); +} +#endif // HAVE_NBGL + +void deriveNativeScriptHash_displayNativeScriptHash_bech32() +{ +#ifdef HAVE_BAGL + ui_displayBech32Screen( + "Script hash", + "script", + ctx->scriptHashBuffer, + SCRIPT_HASH_LENGTH, + deriveNativeScriptHash_displayNativeScriptHash_callback + ); +#elif defined(HAVE_NBGL) + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "script", ctx->scriptHashBuffer, SCRIPT_HASH_LENGTH); + fill_and_display_if_required("Script hash", encodedStr, deriveNativeScriptHash_displayNativeScriptHash_finish, respond_with_user_reject); +#endif // HAVE_BAGL +} + +void deriveNativeScriptHash_displayNativeScriptHash_policyId() +{ +#ifdef HAVE_BAGL + ui_displayHexBufferScreen( + "Policy ID", + ctx->scriptHashBuffer, + SCRIPT_HASH_LENGTH, + deriveNativeScriptHash_displayNativeScriptHash_callback + ); +#elif defined(HAVE_NBGL) + char bufferHex[2 * 32 + 1] = {0}; + ui_getHexBufferScreen(bufferHex, SIZEOF(bufferHex), ctx->scriptHashBuffer, SCRIPT_HASH_LENGTH); + fill_and_display_if_required("Policy ID", bufferHex, deriveNativeScriptHash_displayNativeScriptHash_finish, respond_with_user_reject); +#endif // HAVE_BAGL +} diff --git a/src/deriveNativeScriptHash_ui.h b/src/deriveNativeScriptHash_ui.h new file mode 100644 index 00000000..b5e51fbf --- /dev/null +++ b/src/deriveNativeScriptHash_ui.h @@ -0,0 +1,21 @@ +#ifndef H_CARDANO_APP_DERIVE_NATIVE_SCRIPT_HASH_UI +#define H_CARDANO_APP_DERIVE_NATIVE_SCRIPT_HASH_UI +enum { + DISPLAY_UI_STEP_POSITION = 200, + DISPLAY_UI_STEP_TITLE, +#ifdef HAVE_NBGL + DISPLAY_UI_STEP_SCRIPT_TYPE, +#endif // HAVE_NBGL + DISPLAY_UI_STEP_SCRIPT_CONTENT, + DISPLAY_UI_STEP_RESPOND, + DISPLAY_UI_STEP_INVALID +}; + +void deriveScriptHash_display_ui_runStep(); + +void deriveNativeScriptHash_displayNativeScriptHash_callback(); + +void deriveNativeScriptHash_displayNativeScriptHash_bech32(); + +void deriveNativeScriptHash_displayNativeScriptHash_policyId(); +#endif // H_CARDANO_APP_DERIVE_NATIVE_SCRIPT_HASH_UI From 38842652175be73755fbc2455a1678d688977a86 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 21 Oct 2022 15:04:52 +0200 Subject: [PATCH 020/105] uiScreens: move bagl related functions to uiScreens_bagl file --- src/main.c | 31 ++++++--------------------- src/{uiScreens.c => uiScreens_bagl.c} | 30 +++++++++++++++++++++++++- src/{uiScreens.h => uiScreens_bagl.h} | 6 +++--- 3 files changed, 38 insertions(+), 29 deletions(-) rename src/{uiScreens.c => uiScreens_bagl.c} (96%) rename src/{uiScreens.h => uiScreens_bagl.h} (97%) diff --git a/src/main.c b/src/main.c index 145609dc..18f05d62 100644 --- a/src/main.c +++ b/src/main.c @@ -33,6 +33,12 @@ #include "assert.h" #include "io.h" +#ifdef HAVE_BAGL +#include "uiScreens_bagl.h" +#elif defined(HAVE_NBGL) +#include "uiScreens_nbgl.h" +#endif + // The whole app is designed for a specific api level. // In case there is an api change, first *verify* changes // (especially potential security implications) before bumping @@ -41,31 +47,6 @@ STATIC_ASSERT(CX_APILEVEL >= 9, "bad api level"); static const int INS_NONE = -1; -#ifdef HAVE_BAGL -// ui_idle displays the main menu. Note that your app isn't required to use a -// menu as its idle screen; you can define your own completely custom screen. -void ui_idle(void) -{ - currentInstruction = INS_NONE; - - #if defined(TARGET_NANOS) - nanos_clear_timer(); - h_expert_update(); - // The first argument is the starting index within menu_main, and the last - // argument is a preprocessor. - UX_MENU_DISPLAY(0, menu_main, NULL); - #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) - // reserve a display stack slot if none yet - if (G_ux.stack_count == 0) { - ux_stack_push(); - } - ux_flow_init(0, ux_idle_flow, NULL); - #else - STATIC_ASSERT(false); - #endif -} -#endif - static const uint8_t CLA = 0xD7; // This is the main loop that reads and writes APDUs. It receives request diff --git a/src/uiScreens.c b/src/uiScreens_bagl.c similarity index 96% rename from src/uiScreens.c rename to src/uiScreens_bagl.c index 24057d84..284bb2eb 100644 --- a/src/uiScreens.c +++ b/src/uiScreens_bagl.c @@ -1,4 +1,4 @@ -#include "uiScreens.h" +#ifdef HAVE_BAGL #include "bech32.h" #include "cardano.h" #include "hexUtils.h" @@ -7,7 +7,34 @@ #include "signTx.h" #include "signTxPoolRegistration.h" #include "tokens.h" +#include "state.h" +#include "uiHelpers.h" +#include "menu.h" +static const int INS_NONE = -1; + +// ui_idle displays the main menu. Note that your app isn't required to use a +// menu as its idle screen; you can define your own completely custom screen. +void ui_idle(void) +{ + currentInstruction = INS_NONE; + + #if defined(TARGET_NANOS) + nanos_clear_timer(); + h_expert_update(); + // The first argument is the starting index within menu_main, and the last + // argument is a preprocessor. + UX_MENU_DISPLAY(0, menu_main, NULL); + #elif defined(TARGET_NANOX) || defined(TARGET_NANOS2) + // reserve a display stack slot if none yet + if (G_ux.stack_count == 0) { + ux_stack_push(); + } + ux_flow_init(0, ux_idle_flow, NULL); + #else + STATIC_ASSERT(false); + #endif +} // encodes a buffer into bech32 and displays it (works for bufferSize <= 150 and prefix length <= 12) void ui_displayBech32Screen( @@ -861,3 +888,4 @@ void ui_displayInputScreen( callback ); } +#endif // HAVE_BAGL diff --git a/src/uiScreens.h b/src/uiScreens_bagl.h similarity index 97% rename from src/uiScreens.h rename to src/uiScreens_bagl.h index 83047e73..f4073130 100644 --- a/src/uiScreens.h +++ b/src/uiScreens_bagl.h @@ -1,5 +1,5 @@ -#ifndef H_CARDANO_APP_UI_SCREENS -#define H_CARDANO_APP_UI_SCREENS +#ifndef H_CARDANO_APP_UI_SCREENS_BAGL +#define H_CARDANO_APP_UI_SCREENS_BAGL #include "uiHelpers.h" #include "addressUtilsShelley.h" @@ -173,4 +173,4 @@ void ui_displayInputScreen( ui_callback_fn_t callback ); -#endif // H_CARDANO_APP_UI_SCREENS +#endif // H_CARDANO_APP_UI_SCREENS_BAGL From ef8394eb5c3e042d3b2d27662757627ddd483bf6 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 27 Dec 2022 19:31:18 +0100 Subject: [PATCH 021/105] signCVote: update for Stax --- src/signCVote.c | 144 +-------------------------------- src/signCVote.h | 1 + src/signCVote_ui.c | 196 +++++++++++++++++++++++++++++++++++++++++++++ src/signCVote_ui.h | 40 +++++++++ 4 files changed, 241 insertions(+), 140 deletions(-) create mode 100644 src/signCVote_ui.c create mode 100644 src/signCVote_ui.h diff --git a/src/signCVote.c b/src/signCVote.c index 1cc4c20d..1a865a3e 100644 --- a/src/signCVote.c +++ b/src/signCVote.c @@ -3,11 +3,11 @@ #include "signCVote.h" #include "signTxUtils.h" #include "state.h" -#include "uiScreens.h" +#include "signCVote_ui.h" static ins_sign_cvote_context_t* ctx = &(instructionState.signCVoteContext); -static void advanceStage() +void vote_advanceStage() { TRACE("Advancing cip36 voting stage from: %d", ctx->stage); @@ -35,7 +35,7 @@ static void advanceStage() break; case VOTECAST_STAGE_NONE: - // advanceStage() not supposed to be called after votecast processing is finished + // vote_advanceStage() not supposed to be called after votecast processing is finished ASSERT(false); default: @@ -54,58 +54,6 @@ static inline void CHECK_STAGE(sign_cvote_stage_t expected) } // ============================== INIT ============================== - -enum { - HANDLE_INIT_CONFIRM_START = 100, - HANDLE_INIT_VOTE_PLAN_ID, - HANDLE_INIT_PROPOSAL_INDEX, - HANDLE_INIT_PAYLOAD_TYPE_TAG, - HANDLE_INIT_RESPOND, - HANDLE_INIT_INVALID, -}; - -static void handleInit_ui_runStep() -{ - ui_callback_fn_t* this_fn = handleInit_ui_runStep; - - UI_STEP_BEGIN(ctx->ui_step, this_fn); - - UI_STEP(HANDLE_INIT_CONFIRM_START) { - ui_displayPrompt( - "Start new", - "vote? (CIP-36)", - this_fn, - respond_with_user_reject - ); - } - UI_STEP(HANDLE_INIT_VOTE_PLAN_ID) { - ui_displayHexBufferScreen( - "Vote plan id", - ctx->votePlanId, SIZEOF(ctx->votePlanId), - this_fn - ); - } - UI_STEP(HANDLE_INIT_PROPOSAL_INDEX) { - ui_displayUint64Screen( - "Proposal index", - ctx->proposalIndex, - this_fn - ); - } - UI_STEP(HANDLE_INIT_PAYLOAD_TYPE_TAG) { - ui_displayUint64Screen( - "Payload type tag", - ctx->payloadTypeTag, - this_fn - ); - } - UI_STEP(HANDLE_INIT_RESPOND) { - respondSuccessEmptyMsg(); - advanceStage(); - } - UI_STEP_END(HANDLE_INIT_INVALID); -} - __noinline_due_to_stack__ void signCVote_handleInitAPDU( const uint8_t* wireDataBuffer, size_t wireDataSize @@ -199,43 +147,11 @@ void signCVote_handleVotecastChunkAPDU( respondSuccessEmptyMsg(); if (ctx->remainingVotecastBytes == 0) { - advanceStage(); + vote_advanceStage(); } } // ============================== CONFIRM ============================== - -enum { - HANDLE_CONFIRM_STEP_FINAL_CONFIRM = 200, - HANDLE_CONFIRM_STEP_RESPOND, - HANDLE_CONFIRM_STEP_INVALID, -}; - -static void handleConfirm_ui_runStep() -{ - TRACE("UI step %d", ctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = handleConfirm_ui_runStep; - - UI_STEP_BEGIN(ctx->ui_step, this_fn); - - UI_STEP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM) { - ui_displayPrompt( - "Confirm", - "vote?", - this_fn, - respond_with_user_reject - ); - } - UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { - io_send_buf(SUCCESS, ctx->votecastHash, SIZEOF(ctx->votecastHash)); - ui_displayBusy(); // displays dots, called only after I/O to avoid freezing - - advanceStage(); - } - UI_STEP_END(HANDLE_CONFIRM_STEP_INVALID); -} - __noinline_due_to_stack__ void signCVote_handleConfirmAPDU( const uint8_t* wireDataBuffer MARK_UNUSED, size_t wireDataSize @@ -282,58 +198,6 @@ void signCVote_handleConfirmAPDU( // ============================== WITNESS ============================== -static void _wipeWitnessSignature() -{ - // safer not to keep the signature in memory - explicit_bzero(ctx->witnessData.signature, SIZEOF(ctx->witnessData.signature)); - respond_with_user_reject(); -} - -enum { - HANDLE_WITNESS_STEP_WARNING = 300, - HANDLE_WITNESS_STEP_DISPLAY, - HANDLE_WITNESS_STEP_CONFIRM, - HANDLE_WITNESS_STEP_RESPOND, - HANDLE_WITNESS_STEP_INVALID, -}; - -static void handleWitness_ui_runStep() -{ - TRACE("UI step %d", ctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = handleWitness_ui_runStep; - - UI_STEP_BEGIN(ctx->ui_step, this_fn); - - UI_STEP(HANDLE_WITNESS_STEP_WARNING) { - ui_displayPaginatedText( - "WARNING:", - "unusual witness requested", - this_fn - ); - } - UI_STEP(HANDLE_WITNESS_STEP_DISPLAY) { - ui_displayPathScreen("Witness path", &ctx->witnessData.path, this_fn); - } - UI_STEP(HANDLE_WITNESS_STEP_CONFIRM) { - ui_displayPrompt( - "Sign using", - "this witness?", - this_fn, - _wipeWitnessSignature - ); - } - UI_STEP(HANDLE_WITNESS_STEP_RESPOND) { - TRACE("Sending witness data"); - TRACE_BUFFER(ctx->witnessData.signature, SIZEOF(ctx->witnessData.signature)); - io_send_buf(SUCCESS, ctx->witnessData.signature, SIZEOF(ctx->witnessData.signature)); - ui_displayBusy(); // displays dots, called only after I/O to avoid freezing - - advanceStage(); - } - UI_STEP_END(HANDLE_WITNESS_STEP_INVALID); -} - __noinline_due_to_stack__ void signCVote_handleWitnessAPDU( const uint8_t* wireDataBuffer, size_t wireDataSize diff --git a/src/signCVote.h b/src/signCVote.h index 42eab7dd..627ab3fc 100644 --- a/src/signCVote.h +++ b/src/signCVote.h @@ -42,4 +42,5 @@ typedef struct { handler_fn_t signCVote_handleAPDU; +void vote_advanceStage(); #endif // H_CARDANO_APP_SIGN_CVOTE diff --git a/src/signCVote_ui.c b/src/signCVote_ui.c new file mode 100644 index 00000000..b4a1d912 --- /dev/null +++ b/src/signCVote_ui.c @@ -0,0 +1,196 @@ +#include "messageSigning.h" +#include "securityPolicy.h" +#include "signCVote.h" +#include "signTxUtils.h" +#include "state.h" +#include "signCVote_ui.h" + +#ifdef HAVE_BAGL +#include "uiScreens_bagl.h" +#elif defined(HAVE_NBGL) +#include "uiScreens_nbgl.h" +#include "nbgl_use_case.h" +#endif + + +static ins_sign_cvote_context_t* ctx = &(instructionState.signCVoteContext); + +// ============================== INIT ============================== + +void handleInit_ui_runStep() +{ + ui_callback_fn_t* this_fn = handleInit_ui_runStep; + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + + UI_STEP(HANDLE_INIT_CONFIRM_START) { +#ifdef HAVE_BAGL + ui_displayPrompt( + "Start new", + "vote? (CIP-36)", + this_fn, + respond_with_user_reject + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt("Start new\nvote? (CIP-36)", "", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_INIT_VOTE_PLAN_ID) { +#ifdef HAVE_BAGL + ui_displayHexBufferScreen( + "Vote plan id", + ctx->votePlanId, SIZEOF(ctx->votePlanId), + this_fn + ); +#elif defined(HAVE_NBGL) + char bufferHex[2 * 32 + 1] = {0}; + ui_getHexBufferScreen(bufferHex, SIZEOF(bufferHex), ctx->votePlanId, SIZEOF(ctx->votePlanId)); + fill_and_display_if_required("Vote plan id", bufferHex, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_INIT_PROPOSAL_INDEX) { +#ifdef HAVE_BAGL + ui_displayUint64Screen( + "Proposal index", + ctx->proposalIndex, + this_fn + ); +#elif defined(HAVE_NBGL) + char line[30]; + ui_getUint64Screen( + line, + SIZEOF(line), + ctx->proposalIndex + ); + fill_and_display_if_required("Proposal index", line, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_INIT_PAYLOAD_TYPE_TAG) { +#ifdef HAVE_BAGL + ui_displayUint64Screen( + "Payload type tag", + ctx->payloadTypeTag, + this_fn + ); +#elif defined(HAVE_NBGL) + char line[30]; + ui_getUint64Screen( + line, + SIZEOF(line), + ctx->payloadTypeTag + ); + fill_and_display_if_required("Payload type tag", line, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_INIT_RESPOND) { + respondSuccessEmptyMsg(); + vote_advanceStage(); + } + UI_STEP_END(HANDLE_INIT_INVALID); +} + +// ============================== CONFIRM ============================== + +void handleConfirm_ui_runStep() +{ + TRACE("UI step %d", ctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = handleConfirm_ui_runStep; + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + + UI_STEP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM) { +#ifdef HAVE_BAGL + ui_displayPrompt( + "Confirm", + "vote?", + this_fn, + respond_with_user_reject + ); +#elif defined(HAVE_NBGL) + display_confirmation("Confirm\nvote", "", "VOTE\nCONFIRMED", "Vote\nrejected", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { + io_send_buf(SUCCESS, ctx->votecastHash, SIZEOF(ctx->votecastHash)); +#ifdef HAVE_BAGL + ui_displayBusy(); // displays dots, called only after I/O to avoid freezing +#endif // HAVE_BAGL + + vote_advanceStage(); + } + UI_STEP_END(HANDLE_CONFIRM_STEP_INVALID); +} + +// ============================== WITNESS ============================== + +static void _wipeWitnessSignature() +{ + // safer not to keep the signature in memory + explicit_bzero(ctx->witnessData.signature, SIZEOF(ctx->witnessData.signature)); + respond_with_user_reject(); +} + +void handleWitness_ui_runStep() +{ + TRACE("UI step %d", ctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = handleWitness_ui_runStep; + + UI_STEP_BEGIN(ctx->ui_step, this_fn); + + UI_STEP(HANDLE_WITNESS_STEP_WARNING) { +#ifdef HAVE_BAGL + ui_displayPaginatedText( + "WARNING:", + "unusual witness requested", + this_fn + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning("Unusual\nwitness requested", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_WITNESS_STEP_PROMPT) { +#ifdef HAVE_BAGL + UI_STEP_JUMP(HANDLE_WITNESS_STEP_DISPLAY) +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt("Review witness", "", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_WITNESS_STEP_DISPLAY) { +#ifdef HAVE_BAGL + ui_displayPathScreen("Witness path", &ctx->witnessData.path, this_fn); +#elif defined(HAVE_NBGL) + char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; + ui_getPathScreen(pathStr, SIZEOF(pathStr), &ctx->witnessData.path); + fill_and_display_if_required("Witness path", pathStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_WITNESS_STEP_CONFIRM) { +#ifdef HAVE_BAGL + ui_displayPrompt( + "Sign using", + "this witness?", + this_fn, + _wipeWitnessSignature + ); +#elif defined(HAVE_NBGL) + display_confirmation("Sign\nusing witness", "", "WITNESS\nCONFIRMED", "Witness\nrejected", this_fn, _wipeWitnessSignature); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_WITNESS_STEP_RESPOND) { + TRACE("Sending witness data"); + TRACE_BUFFER(ctx->witnessData.signature, SIZEOF(ctx->witnessData.signature)); + io_send_buf(SUCCESS, ctx->witnessData.signature, SIZEOF(ctx->witnessData.signature)); +#ifdef HAVE_BAGL + ui_displayBusy(); // displays dots, called only after I/O to avoid freezing +#endif // HAVE_BAGL + + vote_advanceStage(); + } + UI_STEP_END(HANDLE_WITNESS_STEP_INVALID); +} + diff --git a/src/signCVote_ui.h b/src/signCVote_ui.h new file mode 100644 index 00000000..d18a1fb0 --- /dev/null +++ b/src/signCVote_ui.h @@ -0,0 +1,40 @@ +#ifndef H_CARDANO_APP_SIGN_CVOTE_UI +#define H_CARDANO_APP_SIGN_CVOTE_UI + +#include "uiHelpers.h" +// ============================== INIT ============================== + +enum { + HANDLE_INIT_CONFIRM_START = 100, + HANDLE_INIT_VOTE_PLAN_ID, + HANDLE_INIT_PROPOSAL_INDEX, + HANDLE_INIT_PAYLOAD_TYPE_TAG, + HANDLE_INIT_RESPOND, + HANDLE_INIT_INVALID, +}; + +void handleInit_ui_runStep(); + +// ============================== CONFIRM ============================== + +enum { + HANDLE_CONFIRM_STEP_FINAL_CONFIRM = 200, + HANDLE_CONFIRM_STEP_RESPOND, + HANDLE_CONFIRM_STEP_INVALID, +}; + +void handleConfirm_ui_runStep(); + +// ============================== WITNESS ============================== + +enum { + HANDLE_WITNESS_STEP_WARNING = 300, + HANDLE_WITNESS_STEP_PROMPT, + HANDLE_WITNESS_STEP_DISPLAY, + HANDLE_WITNESS_STEP_CONFIRM, + HANDLE_WITNESS_STEP_RESPOND, + HANDLE_WITNESS_STEP_INVALID, +}; + +void handleWitness_ui_runStep(); +#endif // H_CARDANO_APP_SIGN_CVOTE_UI From 2f4c8f04037b807dc6ae5d77235e0dd405d28d80 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 27 Dec 2022 19:49:42 +0100 Subject: [PATCH 022/105] signTxCVoteRegistration: update for Stax --- src/signTxCVoteRegistration.c | 307 +---------------------- src/signTxCVoteRegistration.h | 6 + src/signTxCVoteRegistration_ui.c | 406 +++++++++++++++++++++++++++++++ src/signTxCVoteRegistration_ui.h | 86 +++++++ 4 files changed, 503 insertions(+), 302 deletions(-) create mode 100644 src/signTxCVoteRegistration_ui.c create mode 100644 src/signTxCVoteRegistration_ui.h diff --git a/src/signTxCVoteRegistration.c b/src/signTxCVoteRegistration.c index 50bed876..a36e0f6d 100644 --- a/src/signTxCVoteRegistration.c +++ b/src/signTxCVoteRegistration.c @@ -3,13 +3,13 @@ #include "state.h" #include "uiHelpers.h" #include "signTxUtils.h" -#include "uiScreens.h" #include "auxDataHashBuilder.h" #include "txHashBuilder.h" #include "textUtils.h" #include "bufView.h" #include "securityPolicy.h" #include "messageSigning.h" +#include "signTxCVoteRegistration_ui.h" static common_tx_data_t* commonTxData = &(instructionState.signTxContext.commonTxData); @@ -56,7 +56,7 @@ static inline void CHECK_STATE(sign_tx_cvote_registration_state_t expected) VALIDATE(accessSubContext()->state == expected, ERR_INVALID_STATE); } -static inline void advanceState() +void voting_registration_advanceState() { cvote_registration_context_t* subctx = accessSubContext(); TRACE("Advancing CIP-36 voting registration state from: %d", subctx->state); @@ -158,7 +158,7 @@ static void signTxCVoteRegistration_handleInitAPDU(const uint8_t* wireDataBuffer } respondSuccessEmptyMsg(); - advanceState(); + voting_registration_advanceState(); } // ============================== VOTING KEY ============================== @@ -224,66 +224,6 @@ security_policy_t _determineVoteKeyPolicy() return POLICY_DENY; } -static void _displayVoteKey(ui_callback_fn_t callback) -{ - cvote_registration_context_t* subctx = accessSubContext(); - switch (subctx->stateData.delegation.type) { - case DELEGATION_KEY: { - STATIC_ASSERT(SIZEOF(subctx->stateData.delegation.votePubKey) == CVOTE_PUBLIC_KEY_LENGTH, "wrong vote public key size"); - ui_displayBech32Screen( - "Vote public key", - "cvote_vk", - subctx->stateData.delegation.votePubKey, CVOTE_PUBLIC_KEY_LENGTH, - callback - ); - break; - } - case DELEGATION_PATH: { - ui_displayPathScreen( - "Vote public key", - &subctx->stateData.delegation.votePubKeyPath, - callback - ); - break; - } - default: - ASSERT(false); - } -} - -enum { - HANDLE_VOTE_KEY_STEP_WARNING = 8200, - HANDLE_VOTE_KEY_STEP_DISPLAY, - HANDLE_VOTE_KEY_STEP_RESPOND, - HANDLE_VOTE_KEY_STEP_INVALID, -}; - -static void signTxCVoteRegistration_handleVoteKey_ui_runStep() -{ - cvote_registration_context_t* subctx = accessSubContext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTxCVoteRegistration_handleVoteKey_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_VOTE_KEY_STEP_WARNING) { - ui_displayPaginatedText( - "WARNING:", - "unusual vote key", - this_fn - ); - } - UI_STEP(HANDLE_VOTE_KEY_STEP_DISPLAY) { - _displayVoteKey(this_fn); - } - UI_STEP(HANDLE_VOTE_KEY_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_VOTE_KEY_STEP_INVALID); -} - __noinline_due_to_stack__ static void signTxCVoteRegistration_handleVoteKeyAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) { @@ -355,50 +295,6 @@ static void signTxCVoteRegistration_handleVoteKeyAPDU(const uint8_t* wireDataBuf // ============================== DELEGATION ============================== -enum { - HANDLE_DELEGATION_STEP_WARNING = 8300, - HANDLE_DELEGATION_STEP_VOTE_KEY, - HANDLE_DELEGATION_STEP_WEIGHT, - HANDLE_DELEGATION_STEP_RESPOND, - HANDLE_DELEGATION_STEP_INVALID, -}; - -static void signTxCVoteRegistration_handleDelegation_ui_runStep() -{ - cvote_registration_context_t* subctx = accessSubContext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTxCVoteRegistration_handleDelegation_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_VOTE_KEY_STEP_WARNING) { - ui_displayPaginatedText( - "WARNING:", - "unusual vote key", - this_fn - ); - } - UI_STEP(HANDLE_DELEGATION_STEP_VOTE_KEY) { - _displayVoteKey(this_fn); - } - UI_STEP(HANDLE_DELEGATION_STEP_WEIGHT) { - ui_displayUint64Screen( - "Weight", - subctx->stateData.delegation.weight, - this_fn - ); - } - UI_STEP(HANDLE_DELEGATION_STEP_RESPOND) { - respondSuccessEmptyMsg(); - subctx->currentDelegation++; - if (subctx->currentDelegation == subctx->numDelegations) { - advanceState(); - } - } - UI_STEP_END(HANDLE_DELEGATION_STEP_INVALID); -} - __noinline_due_to_stack__ static void signTxCVoteRegistration_handleDelegationAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) { @@ -476,42 +372,6 @@ static void signTxCVoteRegistration_handleDelegationAPDU(const uint8_t* wireData // ============================== STAKING KEY ============================== -enum { - HANDLE_STAKING_KEY_STEP_WARNING = 8400, - HANDLE_STAKING_KEY_STEP_DISPLAY, - HANDLE_STAKING_KEY_STEP_RESPOND, - HANDLE_STAKING_KEY_STEP_INVALID, -}; - -static void signTxCVoteRegistration_handleStakingKey_ui_runStep() -{ - cvote_registration_context_t* subctx = accessSubContext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTxCVoteRegistration_handleStakingKey_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_STAKING_KEY_STEP_WARNING) { - ui_displayPaginatedText( - "Unusual request", - "Proceed with care", - this_fn - ); - } - UI_STEP(HANDLE_STAKING_KEY_STEP_DISPLAY) { - ui_displayStakingKeyScreen( - &subctx->stakingKeyPath, - this_fn - ); - } - UI_STEP(HANDLE_STAKING_KEY_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_STAKING_KEY_STEP_INVALID); -} - __noinline_due_to_stack__ static void signTxCVoteRegistration_handleStakingKeyAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) { @@ -572,7 +432,7 @@ static void signTxCVoteRegistration_handleStakingKeyAPDU(const uint8_t* wireData // ============================== VOTING REWARDS ADDRESS ============================== -static size_t _destinationToAddress( +size_t _destinationToAddress( tx_output_destination_storage_t* destination, uint8_t* addressBuffer, size_t addressBufferSize @@ -606,51 +466,6 @@ static size_t _destinationToAddress( return addressSize; } -enum { - HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_WARNING = 8500, - HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS, - HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_RESPOND, - HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_INVALID -}; - -__noinline_due_to_stack__ -static void signTxCVoteRegistration_handlePaymentAddress_ui_runStep() -{ - cvote_registration_context_t* subctx = accessSubContext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTxCVoteRegistration_handlePaymentAddress_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_WARNING) { - ui_displayPaginatedText( - "Unusual request", - "Proceed with care", - this_fn - ); - } - UI_STEP(HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS) { - uint8_t addressBuffer[MAX_ADDRESS_SIZE] = {0}; - size_t addressSize = _destinationToAddress( - &subctx->stateData.paymentDestination, - addressBuffer, SIZEOF(addressBuffer) - ); - - ui_displayAddressScreen( - "Rewards go to", - addressBuffer, - addressSize, - this_fn - ); - } - UI_STEP(HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_INVALID); -} - __noinline_due_to_stack__ static void signTxCVoteRegistration_handlePaymentAddressAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) { @@ -714,35 +529,6 @@ static void signTxCVoteRegistration_handlePaymentAddressAPDU(const uint8_t* wire // ============================== NONCE ============================== -enum { - HANDLE_NONCE_STEP_DISPLAY = 8600, - HANDLE_NONCE_STEP_RESPOND, - HANDLE_NONCE_STEP_INVALID, -}; - -static void signTxCVoteRegistration_handleNonce_ui_runStep() -{ - cvote_registration_context_t* subctx = accessSubContext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTxCVoteRegistration_handleNonce_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_NONCE_STEP_DISPLAY) { - ui_displayUint64Screen( - "Nonce", - subctx->stateData.nonce, - this_fn - ); - } - UI_STEP(HANDLE_NONCE_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_NONCE_STEP_INVALID); -} - __noinline_due_to_stack__ static void signTxCVoteRegistration_handleNonceAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) { @@ -790,35 +576,6 @@ static void signTxCVoteRegistration_handleNonceAPDU(const uint8_t* wireDataBuffe // ============================== VOTING PURPOSE ============================== -enum { - HANDLE_VOTING_PURPOSE_STEP_DISPLAY = 8700, - HANDLE_VOTING_PURPOSE_STEP_RESPOND, - HANDLE_VOTING_PURPOSE_STEP_INVALID, -}; - -static void signTxCVoteRegistration_handleVotingPurpose_ui_runStep() -{ - cvote_registration_context_t* subctx = accessSubContext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTxCVoteRegistration_handleVotingPurpose_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_VOTING_PURPOSE_STEP_DISPLAY) { - ui_displayUint64Screen( - "Voting purpose", - subctx->stateData.votingPurpose, - this_fn - ); - } - UI_STEP(HANDLE_VOTING_PURPOSE_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_VOTING_PURPOSE_STEP_INVALID); -} - #define DEFAULT_VOTING_PURPOSE (0) __noinline_due_to_stack__ @@ -861,7 +618,7 @@ static void signTxCVoteRegistration_handleVotingPurposeAPDU(const uint8_t* wireD if (subctx->format != CIP36) { // nothing to do, the APDU was only received to simplify the state machine respondSuccessEmptyMsg(); - advanceState(); + voting_registration_advanceState(); return; } @@ -893,60 +650,6 @@ static void signTxCVoteRegistration_handleVotingPurposeAPDU(const uint8_t* wireD // ============================== CONFIRM ============================== -enum { - HANDLE_CONFIRM_STEP_FINAL_CONFIRM = 8800, - HANDLE_CONFIRM_STEP_DISPLAY_HASH, - HANDLE_CONFIRM_STEP_RESPOND, - HANDLE_CONFIRM_STEP_INVALID, -}; - -static void signTxCVoteRegistration_handleConfirm_ui_runStep() -{ - cvote_registration_context_t* subctx = accessSubContext(); - TRACE("UI step %d", subctx->ui_step); - TRACE_STACK_USAGE(); - ui_callback_fn_t* this_fn = signTxCVoteRegistration_handleConfirm_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - UI_STEP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM) { - // confirming this means the signature being sent out of the device - // so we want to show it in non-expert mode too - ui_displayPrompt( - "Confirm vote key", - "registration?", - this_fn, - respond_with_user_reject - ); - } - UI_STEP(HANDLE_CONFIRM_STEP_DISPLAY_HASH) { - if (!app_mode_expert()) { - UI_STEP_JUMP(HANDLE_CONFIRM_STEP_RESPOND); - } - ui_displayHexBufferScreen( - "Auxiliary data hash", - subctx->auxDataHash, - SIZEOF(subctx->auxDataHash), - this_fn - ); - } - UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { - struct { - uint8_t auxDataHash[AUX_DATA_HASH_LENGTH]; - uint8_t signature[ED25519_SIGNATURE_LENGTH]; - } wireResponse = {0}; - - STATIC_ASSERT(SIZEOF(subctx->auxDataHash) == AUX_DATA_HASH_LENGTH, "Wrong aux data hash length"); - memmove(wireResponse.auxDataHash, subctx->auxDataHash, AUX_DATA_HASH_LENGTH); - - STATIC_ASSERT(SIZEOF(subctx->stateData.registrationSignature) == ED25519_SIGNATURE_LENGTH, "Wrong CIP-36 voting registration signature length"); - memmove(wireResponse.signature, subctx->stateData.registrationSignature, ED25519_SIGNATURE_LENGTH); - - io_send_buf(SUCCESS, (uint8_t*) &wireResponse, SIZEOF(wireResponse)); - advanceState(); - } - UI_STEP_END(HANDLE_CONFIRM_STEP_INVALID); -} - __noinline_due_to_stack__ static void signTxCVoteRegistration_handleConfirmAPDU(const uint8_t* wireDataBuffer MARK_UNUSED, size_t wireDataSize) { diff --git a/src/signTxCVoteRegistration.h b/src/signTxCVoteRegistration.h index 1d96dc5d..300ea65b 100644 --- a/src/signTxCVoteRegistration.h +++ b/src/signTxCVoteRegistration.h @@ -67,4 +67,10 @@ void signTxCVoteRegistration_handleAPDU(uint8_t p2, const uint8_t* wireDataBuffe bool signTxCVoteRegistration_isFinished(); +void voting_registration_advanceState(); +size_t _destinationToAddress( + tx_output_destination_storage_t* destination, + uint8_t* addressBuffer, + size_t addressBufferSize +); #endif // H_CARDANO_APP_SIGN_TX_CVOTE_REGISTRATION diff --git a/src/signTxCVoteRegistration_ui.c b/src/signTxCVoteRegistration_ui.c new file mode 100644 index 00000000..5c420170 --- /dev/null +++ b/src/signTxCVoteRegistration_ui.c @@ -0,0 +1,406 @@ +#include "app_mode.h" +#include "signTxCVoteRegistration.h" +#include "state.h" +#include "uiHelpers.h" +#include "signTxUtils.h" +#include "auxDataHashBuilder.h" +#include "txHashBuilder.h" +#include "textUtils.h" +#include "bufView.h" +#include "securityPolicy.h" +#include "messageSigning.h" +#include "signTxCVoteRegistration_ui.h" + +static inline cvote_registration_context_t* accessSubContext() +{ + return &AUX_DATA_CTX->stageContext.cvote_registration_subctx; +} + +// ============================== VOTING KEY ============================== + +static void _displayVoteKey(ui_callback_fn_t callback) +{ + cvote_registration_context_t* subctx = accessSubContext(); + switch (subctx->stateData.delegation.type) { + case DELEGATION_KEY: { + STATIC_ASSERT(SIZEOF(subctx->stateData.delegation.votePubKey) == CVOTE_PUBLIC_KEY_LENGTH, "wrong vote public key size"); +#ifdef HAVE_BAGL + ui_displayBech32Screen( + "Vote public key", + "cvote_vk", + subctx->stateData.delegation.votePubKey, CVOTE_PUBLIC_KEY_LENGTH, + callback + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "cvote_vk", subctx->stateData.delegation.votePubKey, CVOTE_PUBLIC_KEY_LENGTH); + fill_and_display_if_required("Vote public key", encodedStr, callback, respond_with_user_reject); +#endif // HAVE_BAGL + break; + } + case DELEGATION_PATH: { +#ifdef HAVE_BAGL + ui_displayPathScreen( + "Vote public key", + &subctx->stateData.delegation.votePubKeyPath, + callback + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; + ui_getPathScreen(pathStr, SIZEOF(pathStr), &subctx->stateData.delegation.votePubKeyPath); + fill_and_display_if_required("Vote public key", pathStr, callback, respond_with_user_reject); +#endif // HAVE_BAGL + break; + } + default: + ASSERT(false); + } +} + +void signTxCVoteRegistration_handleVoteKey_ui_runStep() +{ + cvote_registration_context_t* subctx = accessSubContext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = signTxCVoteRegistration_handleVoteKey_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_VOTE_KEY_STEP_WARNING) { +#ifdef HAVE_BAGL + ui_displayPaginatedText( + "WARNING:", + "unusual vote key", + this_fn + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning("Unusual\nvote key", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_VOTE_KEY_STEP_DISPLAY) { + _displayVoteKey(this_fn); + } + UI_STEP(HANDLE_VOTE_KEY_STEP_RESPOND) { + respondSuccessEmptyMsg(); + voting_registration_advanceState(); + } + UI_STEP_END(HANDLE_VOTE_KEY_STEP_INVALID); +} + +// ============================== DELEGATION ============================== + +void signTxCVoteRegistration_handleDelegation_ui_runStep() +{ + cvote_registration_context_t* subctx = accessSubContext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = signTxCVoteRegistration_handleDelegation_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_VOTE_KEY_STEP_WARNING) { +#ifdef HAVE_BAGL + ui_displayPaginatedText( + "WARNING:", + "unusual vote key", + this_fn + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning("Unusual\nvote key", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_DELEGATION_STEP_VOTE_KEY) { + _displayVoteKey(this_fn); + } + UI_STEP(HANDLE_DELEGATION_STEP_WEIGHT) { +#ifdef HAVE_BAGL + ui_displayUint64Screen( + "Weight", + subctx->stateData.delegation.weight, + this_fn + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + char line[30]; + ui_getUint64Screen( + line, + SIZEOF(line), + subctx->stateData.delegation.weight + ); + fill_and_display_if_required("Weight", line, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_DELEGATION_STEP_RESPOND) { + respondSuccessEmptyMsg(); + subctx->currentDelegation++; + if (subctx->currentDelegation == subctx->numDelegations) { + voting_registration_advanceState(); + } + } + UI_STEP_END(HANDLE_DELEGATION_STEP_INVALID); +} + +// ============================== STAKING KEY ============================== + +#ifdef HAVE_NBGL +static void signTxCVoteRegistration_handleStakingKey_ui_cb(void) { + cvote_registration_context_t* subctx = accessSubContext(); + char line1[30] = {0}; + char pathStr[MAX(160,BIP44_PATH_STRING_SIZE_MAX + 1)] = {0}; + ui_getPublicKeyPathScreen( + line1, SIZEOF(line1), + pathStr, SIZEOF(pathStr), + &subctx->stakingKeyPath + ); + fill_and_display_if_required(line1, pathStr, signTxCVoteRegistration_handleStakingKey_ui_runStep, respond_with_user_reject); +} +#endif // HAVE_NBGL + +void signTxCVoteRegistration_handleStakingKey_ui_runStep() +{ + cvote_registration_context_t* subctx = accessSubContext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = signTxCVoteRegistration_handleStakingKey_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_STAKING_KEY_STEP_WARNING) { +#ifdef HAVE_BAGL + ui_displayPaginatedText( + "Unusual request", + "Proceed with care", + this_fn + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning("Unusual request\nProceed with care", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_STAKING_KEY_STEP_DISPLAY) { +#ifdef HAVE_BAGL + ui_displayStakingKeyScreen( + &subctx->stakingKeyPath, + this_fn + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + bool showAccountDescription = bip44_isPathReasonable(&subctx->stakingKeyPath); + if (showAccountDescription) { + char line1[30]; + char line2[30]; + ui_getAccountScreeen( + line1, + SIZEOF(line1), + line2, + SIZEOF(line2), + &subctx->stakingKeyPath + ); + fill_and_display_if_required(line1, line2, signTxCVoteRegistration_handleStakingKey_ui_cb, respond_with_user_reject); + } +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_STAKING_KEY_STEP_RESPOND) { + respondSuccessEmptyMsg(); + voting_registration_advanceState(); + } + UI_STEP_END(HANDLE_STAKING_KEY_STEP_INVALID); +} + +// ============================== VOTING REWARDS ADDRESS ============================== + +__noinline_due_to_stack__ +void signTxCVoteRegistration_handlePaymentAddress_ui_runStep() +{ + cvote_registration_context_t* subctx = accessSubContext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = signTxCVoteRegistration_handlePaymentAddress_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_WARNING) { +#ifdef HAVE_BAGL + ui_displayPaginatedText( + "Unusual request", + "Proceed with care", + this_fn + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning("Unusual request\nProceed with care", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS) { + uint8_t addressBuffer[MAX_ADDRESS_SIZE] = {0}; + size_t addressSize = _destinationToAddress( + &subctx->stateData.paymentDestination, + addressBuffer, SIZEOF(addressBuffer) + ); + +#ifdef HAVE_BAGL + ui_displayAddressScreen( + "Rewards go to", + addressBuffer, + addressSize, + this_fn + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + char humanAddress[MAX_HUMAN_ADDRESS_SIZE] = {0}; + ui_getAddressScreen( + humanAddress, + SIZEOF(humanAddress), + addressBuffer, + addressSize + ); + fill_and_display_if_required("Rewards go to", humanAddress, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_RESPOND) { + respondSuccessEmptyMsg(); + voting_registration_advanceState(); + } + UI_STEP_END(HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_INVALID); +} + +// ============================== NONCE ============================== + +void signTxCVoteRegistration_handleNonce_ui_runStep() +{ + cvote_registration_context_t* subctx = accessSubContext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = signTxCVoteRegistration_handleNonce_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_NONCE_STEP_DISPLAY) { +#ifdef HAVE_BAGL + ui_displayUint64Screen( + "Nonce", + subctx->stateData.nonce, + this_fn + ); +#elif defined(HAVE_NBGL) + char line[30]; + ui_getUint64Screen( + line, + SIZEOF(line), + subctx->stateData.nonce + ); + fill_and_display_if_required("Nonce", line, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_NONCE_STEP_RESPOND) { + respondSuccessEmptyMsg(); + voting_registration_advanceState(); + } + UI_STEP_END(HANDLE_NONCE_STEP_INVALID); +} + +// ============================== VOTING PURPOSE ============================== + +void signTxCVoteRegistration_handleVotingPurpose_ui_runStep() +{ + cvote_registration_context_t* subctx = accessSubContext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = signTxCVoteRegistration_handleVotingPurpose_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_VOTING_PURPOSE_STEP_DISPLAY) { +#ifdef HAVE_BAGL + ui_displayUint64Screen( + "Voting purpose", + subctx->stateData.votingPurpose, + this_fn + ); +#elif defined(HAVE_NBGL) + char line[30]; + ui_getUint64Screen( + line, + SIZEOF(line), + subctx->stateData.votingPurpose + ); + fill_and_display_if_required("Voting purpose", line, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_VOTING_PURPOSE_STEP_RESPOND) { + respondSuccessEmptyMsg(); + voting_registration_advanceState(); + } + UI_STEP_END(HANDLE_VOTING_PURPOSE_STEP_INVALID); +} + +// ============================== CONFIRM ============================== + +void signTxCVoteRegistration_handleConfirm_ui_runStep() +{ + cvote_registration_context_t* subctx = accessSubContext(); + TRACE("UI step %d", subctx->ui_step); + TRACE_STACK_USAGE(); + ui_callback_fn_t* this_fn = signTxCVoteRegistration_handleConfirm_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + UI_STEP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM) { + // confirming this means the signature being sent out of the device + // so we want to show it in non-expert mode too +#ifdef HAVE_BAGL + ui_displayPrompt( + "Confirm vote key", + "registration?", + this_fn, + respond_with_user_reject + ); +#elif defined(HAVE_NBGL) + display_confirmation( + "Confirm vote key\nregistration", + "", + "VOTE KEY\nCONFIRMED", + "Vote key\nrejected", + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_CONFIRM_STEP_DISPLAY_HASH) { + if (!app_mode_expert()) { + UI_STEP_JUMP(HANDLE_CONFIRM_STEP_RESPOND); + } +#ifdef HAVE_BAGL + ui_displayHexBufferScreen( + "Auxiliary data hash", + subctx->auxDataHash, + SIZEOF(subctx->auxDataHash), + this_fn + ); +#elif defined(HAVE_NBGL) + char bufferHex[2 * 32 + 1] = {0}; + ui_getHexBufferScreen(bufferHex, SIZEOF(bufferHex), subctx->auxDataHash, SIZEOF(subctx->auxDataHash)); + fill_and_display_if_required("Auxiliary data hash", bufferHex, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { + struct { + uint8_t auxDataHash[AUX_DATA_HASH_LENGTH]; + uint8_t signature[ED25519_SIGNATURE_LENGTH]; + } wireResponse = {0}; + + STATIC_ASSERT(SIZEOF(subctx->auxDataHash) == AUX_DATA_HASH_LENGTH, "Wrong aux data hash length"); + memmove(wireResponse.auxDataHash, subctx->auxDataHash, AUX_DATA_HASH_LENGTH); + + STATIC_ASSERT(SIZEOF(subctx->stateData.registrationSignature) == ED25519_SIGNATURE_LENGTH, "Wrong CIP-36 voting registration signature length"); + memmove(wireResponse.signature, subctx->stateData.registrationSignature, ED25519_SIGNATURE_LENGTH); + + io_send_buf(SUCCESS, (uint8_t*) &wireResponse, SIZEOF(wireResponse)); + voting_registration_advanceState(); + } + UI_STEP_END(HANDLE_CONFIRM_STEP_INVALID); +} + diff --git a/src/signTxCVoteRegistration_ui.h b/src/signTxCVoteRegistration_ui.h new file mode 100644 index 00000000..b71551c8 --- /dev/null +++ b/src/signTxCVoteRegistration_ui.h @@ -0,0 +1,86 @@ +#ifndef H_CARDANO_APP_SIGN_CVOTE_REGISTRATION_UI +#define H_CARDANO_APP_SIGN_CVOTE_REGISTRATION_UI + +#ifdef HAVE_BAGL +#include "uiScreens_bagl.h" +#elif defined(HAVE_NBGL) +#include "uiScreens_nbgl.h" +#endif + +// ============================== VOTING KEY ============================== + +enum { + HANDLE_VOTE_KEY_STEP_WARNING = 8200, + HANDLE_VOTE_KEY_STEP_DISPLAY, + HANDLE_VOTE_KEY_STEP_RESPOND, + HANDLE_VOTE_KEY_STEP_INVALID, +}; + +void signTxCVoteRegistration_handleVoteKey_ui_runStep(); + +// ============================== DELEGATION ============================== + +enum { + HANDLE_DELEGATION_STEP_WARNING = 8300, + HANDLE_DELEGATION_STEP_VOTE_KEY, + HANDLE_DELEGATION_STEP_WEIGHT, + HANDLE_DELEGATION_STEP_RESPOND, + HANDLE_DELEGATION_STEP_INVALID, +}; + +void signTxCVoteRegistration_handleDelegation_ui_runStep(); + +// ============================== STAKING KEY ============================== + +enum { + HANDLE_STAKING_KEY_STEP_WARNING = 8400, + HANDLE_STAKING_KEY_STEP_DISPLAY, + HANDLE_STAKING_KEY_STEP_RESPOND, + HANDLE_STAKING_KEY_STEP_INVALID, +}; + +void signTxCVoteRegistration_handleStakingKey_ui_runStep(); + +// ============================== VOTING REWARDS ADDRESS ============================== + +enum { + HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_WARNING = 8500, + HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS, + HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_RESPOND, + HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_INVALID +}; + +__noinline_due_to_stack__ +void signTxCVoteRegistration_handlePaymentAddress_ui_runStep(); + +// ============================== NONCE ============================== + +enum { + HANDLE_NONCE_STEP_DISPLAY = 8600, + HANDLE_NONCE_STEP_RESPOND, + HANDLE_NONCE_STEP_INVALID, +}; + +void signTxCVoteRegistration_handleNonce_ui_runStep(); + +// ============================== VOTING PURPOSE ============================== + +enum { + HANDLE_VOTING_PURPOSE_STEP_DISPLAY = 8700, + HANDLE_VOTING_PURPOSE_STEP_RESPOND, + HANDLE_VOTING_PURPOSE_STEP_INVALID, +}; + +void signTxCVoteRegistration_handleVotingPurpose_ui_runStep(); + +// ============================== CONFIRM ============================== + +enum { + HANDLE_CONFIRM_STEP_FINAL_CONFIRM = 8800, + HANDLE_CONFIRM_STEP_DISPLAY_HASH, + HANDLE_CONFIRM_STEP_RESPOND, + HANDLE_CONFIRM_STEP_INVALID, +}; + +void signTxCVoteRegistration_handleConfirm_ui_runStep(); +#endif // H_CARDANO_APP_SIGN_CVOTE_REGISTRATION_UI From 548099c72de3b55af513eb259b72f2bb0b09ddd0 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 28 Dec 2022 10:29:10 +0100 Subject: [PATCH 023/105] signTxOutput: update for stax --- src/signTxOutput.c | 366 +--------------------------------- src/signTxOutput.h | 1 + src/signTxOutput_ui.c | 452 ++++++++++++++++++++++++++++++++++++++++++ src/signTxOutput_ui.h | 93 +++++++++ 4 files changed, 551 insertions(+), 361 deletions(-) create mode 100644 src/signTxOutput_ui.c create mode 100644 src/signTxOutput_ui.h diff --git a/src/signTxOutput.c b/src/signTxOutput.c index 7ebb10f6..57954284 100644 --- a/src/signTxOutput.c +++ b/src/signTxOutput.c @@ -2,13 +2,13 @@ #include "state.h" #include "uiHelpers.h" #include "signTxUtils.h" -#include "uiScreens.h" #include "txHashBuilder.h" #include "textUtils.h" #include "bufView.h" #include "securityPolicy.h" #include "tokens.h" #include "hexUtils.h" +#include "signTxOutput_ui.h" static common_tx_data_t* commonTxData = &(instructionState.signTxContext.commonTxData); static ins_sign_tx_context_t* ctx = &(instructionState.signTxContext); @@ -57,7 +57,7 @@ static inline void CHECK_STATE(sign_tx_output_state_t expected) VALIDATE(subctx->state == expected, ERR_INVALID_STATE); } -static inline void advanceState() +void tx_output_advanceState() { output_context_t* subctx = accessSubcontext(); TRACE("Advancing output state from: %d", subctx->state); @@ -170,74 +170,6 @@ static inline void advanceState() // ============================== TOP LEVEL DATA ============================== -enum { - HANDLE_OUTPUT_ADDRESS_BYTES_STEP_WARNING_DATUM = 3100, - HANDLE_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADDRESS, - HANDLE_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADA_AMOUNT, - HANDLE_OUTPUT_ADDRESS_BYTES_STEP_RESPOND, - HANDLE_OUTPUT_ADDRESS_BYTES_STEP_INVALID, -}; - -static bool _needsMissingDatumWarning() -{ - output_context_t* subctx = accessSubcontext(); - tx_output_destination_t destination; - destination.type = subctx->stateData.destination.type; - switch (destination.type) { - case DESTINATION_DEVICE_OWNED: - destination.params = &subctx->stateData.destination.params; - break; - case DESTINATION_THIRD_PARTY: - destination.address.buffer = subctx->stateData.destination.address.buffer; - destination.address.size = subctx->stateData.destination.address.size; - break; - } - - return needsMissingDatumWarning(&destination, subctx->includeDatum); -} - -static void signTx_handleOutput_address_bytes_ui_runStep() -{ - output_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - ui_callback_fn_t* this_fn = signTx_handleOutput_address_bytes_ui_runStep; - - ASSERT(subctx->stateData.destination.type == DESTINATION_THIRD_PARTY); - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADDRESS) { - ASSERT(subctx->stateData.destination.address.size <= SIZEOF(subctx->stateData.destination.address.buffer)); - ui_displayAddressScreen( - "Send to address", - subctx->stateData.destination.address.buffer, - subctx->stateData.destination.address.size, - this_fn - ); - } - UI_STEP(HANDLE_OUTPUT_ADDRESS_BYTES_STEP_WARNING_DATUM) { - // this warning does not apply to address given by params where we only allow key hash spending part - // in which case datum is just optional and rarely used - if (_needsMissingDatumWarning()) { - ui_displayPaginatedText( - "WARNING: output", - "could be unspendable due to missing datum", - this_fn - ); - } else { - UI_STEP_JUMP(HANDLE_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADA_AMOUNT); - } - } - UI_STEP(HANDLE_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADA_AMOUNT) { - ui_displayAdaAmountScreen("Send", subctx->stateData.adaAmount, this_fn); - } - UI_STEP(HANDLE_OUTPUT_ADDRESS_BYTES_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_OUTPUT_ADDRESS_BYTES_STEP_INVALID); -} - static void handleOutput_addressBytes() { output_context_t* subctx = accessSubcontext(); @@ -289,63 +221,6 @@ static void handleOutput_addressBytes() } -enum { - HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_BEGIN = 3200, - HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_WARNING_DATUM, - HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_SPENDING_PATH, - HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_STAKING_INFO, - HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS, - HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_AMOUNT, - HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_RESPOND, - HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_INVALID, -}; - -__noinline_due_to_stack__ -static void signTx_handleOutput_addressParams_ui_runStep() -{ - output_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - ui_callback_fn_t* this_fn = signTx_handleOutput_addressParams_ui_runStep; - - ASSERT(subctx->stateData.destination.type == DESTINATION_DEVICE_OWNED); - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_BEGIN) { - ui_displayPaginatedText(subctx->ui_text1, subctx->ui_text2, this_fn); - } - UI_STEP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_SPENDING_PATH) { - ui_displaySpendingInfoScreen(&subctx->stateData.destination.params, this_fn); - } - UI_STEP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_STAKING_INFO) { - ui_displayStakingInfoScreen(&subctx->stateData.destination.params, this_fn); - } - UI_STEP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS) { - uint8_t addressBuffer[MAX_ADDRESS_SIZE] = {0}; - size_t addressSize = deriveAddress(&subctx->stateData.destination.params, addressBuffer, SIZEOF(addressBuffer)); - ASSERT(addressSize > 0); - ASSERT(addressSize <= MAX_ADDRESS_SIZE); - - ui_displayAddressScreen( - subctx->ui_text3, - addressBuffer, addressSize, - this_fn - ); - } - UI_STEP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_AMOUNT) { - if (subctx->stateData.adaAmountSecurityPolicy == POLICY_ALLOW_WITHOUT_PROMPT) { - UI_STEP_JUMP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_RESPOND); - } else { - ui_displayAdaAmountScreen(subctx->ui_text4, subctx->stateData.adaAmount, this_fn); - } - } - UI_STEP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_INVALID); -} - static void handleOutput_addressParams() { output_context_t* subctx = accessSubcontext(); @@ -503,54 +378,6 @@ static void handleTopLevelDataAPDU_output(const uint8_t* wireDataBuffer, size_t }; } -enum { - HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_INTRO = 3300, - HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADDRESS, - HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADA_AMOUNT, - HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_RESPOND, - HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_INVALID, -}; - -static void signTx_handleCollateralOutput_addressBytes_ui_runStep() -{ - output_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - ui_callback_fn_t* this_fn = signTx_handleCollateralOutput_addressBytes_ui_runStep; - - ASSERT(subctx->stateData.destination.type == DESTINATION_THIRD_PARTY); - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_INTRO) { - ui_displayPaginatedText( - "Collateral", - "return output", - this_fn - ); - } - UI_STEP(HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADDRESS) { - ASSERT(subctx->stateData.destination.address.size <= SIZEOF(subctx->stateData.destination.address.buffer)); - ui_displayAddressScreen( - "Address", - subctx->stateData.destination.address.buffer, - subctx->stateData.destination.address.size, - this_fn - ); - } - UI_STEP(HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADA_AMOUNT) { - if (subctx->stateData.adaAmountSecurityPolicy == POLICY_ALLOW_WITHOUT_PROMPT) { - UI_STEP_JUMP(HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_RESPOND); - } else { - ui_displayAdaAmountScreen("Amount", subctx->stateData.adaAmount, this_fn); - } - } - UI_STEP(HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_INVALID); -} - static void handleCollateralOutput_addressBytes() { output_context_t* subctx = accessSubcontext(); @@ -783,55 +610,12 @@ static void handleAssetGroupAPDU(const uint8_t* wireDataBuffer, size_t wireDataS { // no UI, tokens are shown via fingerprints respondSuccessEmptyMsg(); - advanceState(); + tx_output_advanceState(); } } // ============================== TOKEN ============================== -enum { - HANDLE_TOKEN_STEP_DISPLAY_NAME = 3400, - HANDLE_TOKEN_STEP_DISPLAY_AMOUNT, - HANDLE_TOKEN_STEP_RESPOND, - HANDLE_TOKEN_STEP_INVALID, -}; - -static void handleToken_ui_runStep() -{ - output_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - ui_callback_fn_t* this_fn = handleToken_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_TOKEN_STEP_DISPLAY_NAME) { - ui_displayAssetFingerprintScreen( - &subctx->stateData.tokenGroup, - subctx->stateData.token.assetNameBytes, subctx->stateData.token.assetNameSize, - this_fn - ); - } - UI_STEP(HANDLE_TOKEN_STEP_DISPLAY_AMOUNT) { - ui_displayTokenAmountOutputScreen( - &subctx->stateData.tokenGroup, - subctx->stateData.token.assetNameBytes, subctx->stateData.token.assetNameSize, - subctx->stateData.token.amount, - this_fn - ); - } - UI_STEP(HANDLE_TOKEN_STEP_RESPOND) { - respondSuccessEmptyMsg(); - - ASSERT(subctx->stateData.currentToken < subctx->stateData.numTokens); - subctx->stateData.currentToken++; - - if (subctx->stateData.currentToken == subctx->stateData.numTokens) { - advanceState(); - } - } - UI_STEP_END(HANDLE_TOKEN_STEP_INVALID); -} - static void handleTokenAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) { { @@ -915,35 +699,6 @@ static void handleTokenAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) // ========================== DATUM ============================= -enum { - HANDLE_DATUM_HASH_STEP_DISPLAY = 3500, - HANDLE_DATUM_HASH_STEP_RESPOND, - HANDLE_DATUM_HASH_STEP_INVALID, -}; - -static void signTxOutput_handleDatumHash_ui_runStep() -{ - output_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - ui_callback_fn_t* this_fn = signTxOutput_handleDatumHash_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_DATUM_HASH_STEP_DISPLAY) { - ui_displayBech32Screen( - "Datum hash", - "datum", - subctx->stateData.datumHash, OUTPUT_DATUM_HASH_LENGTH, - this_fn - ); - } - UI_STEP(HANDLE_DATUM_HASH_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_DATUM_HASH_STEP_INVALID); -} - static void handleDatumHash(read_view_t* view) { output_context_t* subctx = accessSubcontext(); @@ -981,48 +736,6 @@ static void handleDatumHash(read_view_t* view) } } -enum { - HANDLE_DATUM_INLINE_STEP_DISPLAY = 3600, - HANDLE_DATUM_INLINE_STEP_RESPOND, - HANDLE_DATUM_INLINE_STEP_INVALID, -}; - -__noinline_due_to_stack__ -static void signTxOutput_handleDatumInline_ui_runStep() -{ - output_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - ui_callback_fn_t* this_fn = signTxOutput_handleDatumInline_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_DATUM_INLINE_STEP_DISPLAY) { - char l1[30]; - size_t datumSize = subctx->stateData.datumRemainingBytes + subctx->stateData.datumChunkSize; - // datumSize with 6 digits fits on the screen, less than max tx size - // if more is needed, "bytes" can be replaced by "B" for those larger numbers - snprintf(l1, SIZEOF(l1), "Datum %u bytes", datumSize); - ASSERT(strlen(l1) + 1 < SIZEOF(l1)); - - char l2[20]; - size_t prefixLength = MIN(subctx->stateData.datumChunkSize, 6); - size_t len = encode_hex(subctx->stateData.datumChunk, prefixLength, l2, SIZEOF(l2)); - snprintf(l2 + len, SIZEOF(l2) - len, "..."); - ASSERT(strlen(l2) + 1 < SIZEOF(l2)); - - ui_displayPaginatedText( - l1, - l2, - this_fn - ); - } - UI_STEP(HANDLE_DATUM_INLINE_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_DATUM_INLINE_STEP_INVALID); -} - static void handleDatumInline(read_view_t* view) { output_context_t* subctx = accessSubcontext(); @@ -1147,52 +860,12 @@ static void handleDatumChunkAPDU(const uint8_t* wireDataBuffer, size_t wireDataS } respondSuccessEmptyMsg(); if (subctx->stateData.datumRemainingBytes == 0) { - advanceState(); + tx_output_advanceState(); } } // ========================== REFERENCE SCRIPT ============================= -enum { - HANDLE_SCRIPT_REF_STEP_DISPLAY = 3700, - HANDLE_SCRIPT_REF_STEP_RESPOND, - HANDLE_SCRIPT_REF_STEP_INVALID, -}; - -static void handleRefScript_ui_runStep() -{ - output_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - ui_callback_fn_t* this_fn = handleRefScript_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - UI_STEP(HANDLE_SCRIPT_REF_STEP_DISPLAY) { - char l1[30]; - size_t scriptSize = subctx->stateData.refScriptRemainingBytes + subctx->stateData.refScriptChunkSize; - // scriptSize with 6 digits fits on the screen, less than max tx size - // if more is needed, "bytes" can be replaced by "B" for those larger numbers - snprintf(l1, SIZEOF(l1), "Script %u bytes", scriptSize); - ASSERT(strlen(l1) + 1 < SIZEOF(l1)); - - char l2[20]; - size_t prefixLength = MIN(subctx->stateData.refScriptChunkSize, 6); - size_t len = encode_hex(subctx->stateData.scriptChunk, prefixLength, l2, SIZEOF(l2)); - snprintf(l2 + len, SIZEOF(l2) - len, "..."); - ASSERT(strlen(l2) + 1 < SIZEOF(l2)); - - ui_displayPaginatedText( - l1, - l2, - this_fn - ); - } - UI_STEP(HANDLE_SCRIPT_REF_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_SCRIPT_REF_STEP_INVALID); -} - static void handleRefScriptAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) { { @@ -1293,41 +966,12 @@ static void handleRefScriptChunkAPDU(const uint8_t* wireDataBuffer, size_t wireD } respondSuccessEmptyMsg(); if (subctx->stateData.refScriptRemainingBytes == 0) { - advanceState(); + tx_output_advanceState(); } } // ============================== CONFIRM ============================== -enum { - HANDLE_CONFIRM_STEP_FINAL_CONFIRM = 3800, - HANDLE_CONFIRM_STEP_RESPOND, - HANDLE_CONFIRM_STEP_INVALID, -}; - -static void signTxOutput_handleConfirm_ui_runStep() -{ - output_context_t* subctx = accessSubcontext(); - TRACE("UI step %d", subctx->ui_step); - ui_callback_fn_t* this_fn = signTxOutput_handleConfirm_ui_runStep; - - UI_STEP_BEGIN(subctx->ui_step, this_fn); - - UI_STEP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM) { - ui_displayPrompt( - subctx->ui_text1, - subctx->ui_text2, - this_fn, - respond_with_user_reject - ); - } - UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { - respondSuccessEmptyMsg(); - advanceState(); - } - UI_STEP_END(HANDLE_CONFIRM_STEP_INVALID); -} - static void handleConfirmAPDU_output(const uint8_t* wireDataBuffer MARK_UNUSED, size_t wireDataSize) { { diff --git a/src/signTxOutput.h b/src/signTxOutput.h index 0826e001..5439bd62 100644 --- a/src/signTxOutput.h +++ b/src/signTxOutput.h @@ -102,4 +102,5 @@ void signTxOutput_handleAPDU(uint8_t p2, const uint8_t* wireDataBuffer, size_t w bool signTxCollateralOutput_isValidInstruction(uint8_t p2); void signTxCollateralOutput_handleAPDU(uint8_t p2, const uint8_t* wireDataBuffer, size_t wireDataSize); +void tx_output_advanceState(); #endif // H_CARDANO_APP_SIGN_TX_OUTPUT diff --git a/src/signTxOutput_ui.c b/src/signTxOutput_ui.c new file mode 100644 index 00000000..f2e130c1 --- /dev/null +++ b/src/signTxOutput_ui.c @@ -0,0 +1,452 @@ +#include "signTxOutput.h" +#include "state.h" +#include "uiHelpers.h" +#include "signTxUtils.h" +#include "txHashBuilder.h" +#include "textUtils.h" +#include "bufView.h" +#include "securityPolicy.h" +#include "tokens.h" +#include "hexUtils.h" +#include "signTxOutput_ui.h" + +static output_context_t* accessSubcontext() +{ + return &BODY_CTX->stageContext.output_subctx; +} + +// ============================== TOP LEVEL DATA ============================== + +static bool _needsMissingDatumWarning() +{ + output_context_t* subctx = accessSubcontext(); + tx_output_destination_t destination; + destination.type = subctx->stateData.destination.type; + switch (destination.type) { + case DESTINATION_DEVICE_OWNED: + destination.params = &subctx->stateData.destination.params; + break; + case DESTINATION_THIRD_PARTY: + destination.address.buffer = subctx->stateData.destination.address.buffer; + destination.address.size = subctx->stateData.destination.address.size; + break; + } + + return needsMissingDatumWarning(&destination, subctx->includeDatum); +} + +void signTx_handleOutput_address_bytes_ui_runStep() +{ + output_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + ui_callback_fn_t* this_fn = signTx_handleOutput_address_bytes_ui_runStep; + + ASSERT(subctx->stateData.destination.type == DESTINATION_THIRD_PARTY); + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADDRESS) { + ASSERT(subctx->stateData.destination.address.size <= SIZEOF(subctx->stateData.destination.address.buffer)); +#ifdef HAVE_BAGL + ui_displayAddressScreen( + "Send to address", + subctx->stateData.destination.address.buffer, + subctx->stateData.destination.address.size, + this_fn + ); +#elif defined(HAVE_NBGL) + char humanAddress[MAX_HUMAN_ADDRESS_SIZE] = {0}; + ui_getAddressScreen( + humanAddress, + SIZEOF(humanAddress), + subctx->stateData.destination.address.buffer, + subctx->stateData.destination.address.size + ); + fill_and_display_if_required("Send to address", humanAddress, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_OUTPUT_ADDRESS_BYTES_STEP_WARNING_DATUM) { + // this warning does not apply to address given by params where we only allow key hash spending part + // in which case datum is just optional and rarely used + if (_needsMissingDatumWarning()) { +#ifdef HAVE_BAGL + ui_displayPaginatedText( + "WARNING: output", + "could be unspendable due to missing datum", + this_fn + ); +#elif defined(HAVE_NBGL) + display_warning( + "Output could be unspendable\ndue to missing datum", + this_fn, + respond_with_user_reject + ); +#endif // HAVE_BAGL + } else { + UI_STEP_JUMP(HANDLE_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADA_AMOUNT); + } + } + UI_STEP(HANDLE_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADA_AMOUNT) { +#ifdef HAVE_BAGL + ui_displayAdaAmountScreen("Send", subctx->stateData.adaAmount, this_fn); +#elif defined(HAVE_NBGL) + char adaAmountStr[50] = {0}; + ui_getAdaAmountScreen(adaAmountStr, SIZEOF(adaAmountStr), subctx->stateData.adaAmount); + fill_and_display_if_required("Send", adaAmountStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_OUTPUT_ADDRESS_BYTES_STEP_RESPOND) { + respondSuccessEmptyMsg(); + tx_output_advanceState(); + } + UI_STEP_END(HANDLE_OUTPUT_ADDRESS_BYTES_STEP_INVALID); +} + +void signTx_handleOutput_addressParams_ui_runStep() +{ + output_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + ui_callback_fn_t* this_fn = signTx_handleOutput_addressParams_ui_runStep; + + ASSERT(subctx->stateData.destination.type == DESTINATION_DEVICE_OWNED); + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_BEGIN) { +#ifdef HAVE_BAGL + ui_displayPaginatedText(subctx->ui_text1, subctx->ui_text2, this_fn); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt("Change output", "", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_SPENDING_PATH) { +#ifdef HAVE_BAGL + ui_displaySpendingInfoScreen(&subctx->stateData.destination.params, this_fn); +#elif defined(HAVE_NBGL) +#define SPENDING_INFO_SIZE MAX(11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX, 2 * BECH32_BUFFER_SIZE_MAX) + char line1[30]; + char spendingInfo[SPENDING_INFO_SIZE] = {0}; + ui_getSpendingInfoScreen(line1, SIZEOF(line1), spendingInfo, SIZEOF(spendingInfo), &subctx->stateData.destination.params); + fill_and_display_if_required(line1, spendingInfo, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_STAKING_INFO) { +#ifdef HAVE_BAGL + ui_displayStakingInfoScreen(&subctx->stateData.destination.params, this_fn); +#elif defined(HAVE_NBGL) + char line1[30] = {0}; + char stakingInfo[120] = {0}; + ui_getStakingInfoScreen(line1, SIZEOF(line1), stakingInfo, SIZEOF(stakingInfo), &subctx->stateData.destination.params); + fill_and_display_if_required(line1, stakingInfo, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS) { + uint8_t addressBuffer[MAX_ADDRESS_SIZE] = {0}; + size_t addressSize = deriveAddress(&subctx->stateData.destination.params, addressBuffer, SIZEOF(addressBuffer)); + ASSERT(addressSize > 0); + ASSERT(addressSize <= MAX_ADDRESS_SIZE); + +#ifdef HAVE_BAGL + ui_displayAddressScreen( + subctx->ui_text3, + addressBuffer, addressSize, + this_fn + ); +#elif defined(HAVE_NBGL) + char humanAddress[MAX_HUMAN_ADDRESS_SIZE] = {0}; + ui_getAddressScreen( + humanAddress, + SIZEOF(humanAddress), + addressBuffer, + addressSize + ); + fill_and_display_if_required("Address", humanAddress, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_AMOUNT) { + if (subctx->stateData.adaAmountSecurityPolicy == POLICY_ALLOW_WITHOUT_PROMPT) { + UI_STEP_JUMP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_RESPOND); + } else { +#ifdef HAVE_BAGL + ui_displayAdaAmountScreen(subctx->ui_text4, subctx->stateData.adaAmount, this_fn); +#elif defined(HAVE_NBGL) + char adaAmountStr[50] = {0}; + ui_getAdaAmountScreen(adaAmountStr, SIZEOF(adaAmountStr), subctx->stateData.adaAmount); + fill_and_display_if_required(subctx->ui_text4, adaAmountStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + } + UI_STEP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_RESPOND) { + respondSuccessEmptyMsg(); + tx_output_advanceState(); + } + UI_STEP_END(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_INVALID); +} + +void signTx_handleCollateralOutput_addressBytes_ui_runStep() +{ + output_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + ui_callback_fn_t* this_fn = signTx_handleCollateralOutput_addressBytes_ui_runStep; + + ASSERT(subctx->stateData.destination.type == DESTINATION_THIRD_PARTY); + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_INTRO) { +#ifdef HAVE_BAGL + ui_displayPaginatedText( + "Collateral", + "return output", + this_fn + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt("Collateral\nreturn output", "", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADDRESS) { + ASSERT(subctx->stateData.destination.address.size <= SIZEOF(subctx->stateData.destination.address.buffer)); +#ifdef HAVE_BAGL + ui_displayAddressScreen( + "Address", + subctx->stateData.destination.address.buffer, + subctx->stateData.destination.address.size, + this_fn + ); +#elif defined(HAVE_NBGL) + char humanAddress[MAX_HUMAN_ADDRESS_SIZE] = {0}; + ui_getAddressScreen( + humanAddress, + SIZEOF(humanAddress), + subctx->stateData.destination.address.buffer, + subctx->stateData.destination.address.size + ); + fill_and_display_if_required("Address", humanAddress, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADA_AMOUNT) { + if (subctx->stateData.adaAmountSecurityPolicy == POLICY_ALLOW_WITHOUT_PROMPT) { + UI_STEP_JUMP(HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_RESPOND); + } else { +#ifdef HAVE_BAGL + ui_displayAdaAmountScreen("Amount", subctx->stateData.adaAmount, this_fn); +#elif defined(HAVE_NBGL) + char adaAmountStr[50] = {0}; + ui_getAdaAmountScreen(adaAmountStr, SIZEOF(adaAmountStr), subctx->stateData.adaAmount); + fill_and_display_if_required("Amount", adaAmountStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + } + UI_STEP(HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_RESPOND) { + respondSuccessEmptyMsg(); + tx_output_advanceState(); + } + UI_STEP_END(HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_INVALID); +} + +// ============================== TOKEN ============================== + +void handleToken_ui_runStep() +{ + output_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + ui_callback_fn_t* this_fn = handleToken_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_TOKEN_STEP_DISPLAY_NAME) { +#ifdef HAVE_BAGL + ui_displayAssetFingerprintScreen( + &subctx->stateData.tokenGroup, + subctx->stateData.token.assetNameBytes, subctx->stateData.token.assetNameSize, + this_fn + ); +#elif defined(HAVE_NBGL) + char fingerprint[200] = {0}; + ui_getAssetFingerprintScreen( + fingerprint, + SIZEOF(fingerprint), + &subctx->stateData.tokenGroup, + subctx->stateData.token.assetNameBytes, subctx->stateData.token.assetNameSize + ); + fill_and_display_if_required("Asset fingerprint", fingerprint, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_TOKEN_STEP_DISPLAY_AMOUNT) { +#ifdef HAVE_BAGL + ui_displayTokenAmountOutputScreen( + &subctx->stateData.tokenGroup, + subctx->stateData.token.assetNameBytes, subctx->stateData.token.assetNameSize, + subctx->stateData.token.amount, + this_fn + ); +#elif defined(HAVE_NBGL) + char tokenAmountStr[70] = {0}; + ui_getTokenAmountOutputScreen( + tokenAmountStr, + SIZEOF(tokenAmountStr), + &subctx->stateData.tokenGroup, + subctx->stateData.token.assetNameBytes, subctx->stateData.token.assetNameSize, + subctx->stateData.token.amount + ); + fill_and_display_if_required("Token amount", tokenAmountStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_TOKEN_STEP_RESPOND) { + respondSuccessEmptyMsg(); + + ASSERT(subctx->stateData.currentToken < subctx->stateData.numTokens); + subctx->stateData.currentToken++; + + if (subctx->stateData.currentToken == subctx->stateData.numTokens) { + tx_output_advanceState(); + } + } + UI_STEP_END(HANDLE_TOKEN_STEP_INVALID); +} + +// ========================== DATUM ============================= + +void signTxOutput_handleDatumHash_ui_runStep() +{ + output_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + ui_callback_fn_t* this_fn = signTxOutput_handleDatumHash_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_DATUM_HASH_STEP_DISPLAY) { +#ifdef HAVE_BAGL + ui_displayBech32Screen( + "Datum hash", + "datum", + subctx->stateData.datumHash, OUTPUT_DATUM_HASH_LENGTH, + this_fn + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "datum", subctx->stateData.datumHash, OUTPUT_DATUM_HASH_LENGTH); + fill_and_display_if_required("Datum hash", encodedStr, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_DATUM_HASH_STEP_RESPOND) { + respondSuccessEmptyMsg(); + tx_output_advanceState(); + } + UI_STEP_END(HANDLE_DATUM_HASH_STEP_INVALID); +} + +void signTxOutput_handleDatumInline_ui_runStep() +{ + output_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + ui_callback_fn_t* this_fn = signTxOutput_handleDatumInline_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_DATUM_INLINE_STEP_DISPLAY) { + char l1[30]; + size_t datumSize = subctx->stateData.datumRemainingBytes + subctx->stateData.datumChunkSize; + // datumSize with 6 digits fits on the screen, less than max tx size + // if more is needed, "bytes" can be replaced by "B" for those larger numbers + snprintf(l1, SIZEOF(l1), "Datum %u bytes", datumSize); + ASSERT(strlen(l1) + 1 < SIZEOF(l1)); + + char l2[20]; + size_t prefixLength = MIN(subctx->stateData.datumChunkSize, 6); + size_t len = encode_hex(subctx->stateData.datumChunk, prefixLength, l2, SIZEOF(l2)); + snprintf(l2 + len, SIZEOF(l2) - len, "..."); + ASSERT(strlen(l2) + 1 < SIZEOF(l2)); + +#ifdef HAVE_BAGL + ui_displayPaginatedText( + l1, + l2, + this_fn + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt(l1, l2, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_DATUM_INLINE_STEP_RESPOND) { + respondSuccessEmptyMsg(); + tx_output_advanceState(); + } + UI_STEP_END(HANDLE_DATUM_INLINE_STEP_INVALID); +} + +// ========================== REFERENCE SCRIPT ============================= + +void handleRefScript_ui_runStep() +{ + output_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + ui_callback_fn_t* this_fn = handleRefScript_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + UI_STEP(HANDLE_SCRIPT_REF_STEP_DISPLAY) { + char l1[30]; + size_t scriptSize = subctx->stateData.refScriptRemainingBytes + subctx->stateData.refScriptChunkSize; + // scriptSize with 6 digits fits on the screen, less than max tx size + // if more is needed, "bytes" can be replaced by "B" for those larger numbers + snprintf(l1, SIZEOF(l1), "Script %u bytes", scriptSize); + ASSERT(strlen(l1) + 1 < SIZEOF(l1)); + + char l2[20]; + size_t prefixLength = MIN(subctx->stateData.refScriptChunkSize, 6); + size_t len = encode_hex(subctx->stateData.scriptChunk, prefixLength, l2, SIZEOF(l2)); + snprintf(l2 + len, SIZEOF(l2) - len, "..."); + ASSERT(strlen(l2) + 1 < SIZEOF(l2)); + +#ifdef HAVE_BAGL + ui_displayPaginatedText( + l1, + l2, + this_fn + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt(l1, l2, this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_SCRIPT_REF_STEP_RESPOND) { + respondSuccessEmptyMsg(); + tx_output_advanceState(); + } + UI_STEP_END(HANDLE_SCRIPT_REF_STEP_INVALID); +} + +// ============================== CONFIRM ============================== + +void signTxOutput_handleConfirm_ui_runStep() +{ + output_context_t* subctx = accessSubcontext(); + TRACE("UI step %d", subctx->ui_step); + ui_callback_fn_t* this_fn = signTxOutput_handleConfirm_ui_runStep; + + UI_STEP_BEGIN(subctx->ui_step, this_fn); + + UI_STEP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM) { +#ifdef HAVE_BAGL + ui_displayPrompt( + subctx->ui_text1, + subctx->ui_text2, + this_fn, + respond_with_user_reject + ); +#elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_confirmation("Confirm output", "", "OUTPUT\nCONFIRMED", "Output\nrejected", this_fn, respond_with_user_reject); +#endif // HAVE_BAGL + } + UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { + respondSuccessEmptyMsg(); + tx_output_advanceState(); + } + UI_STEP_END(HANDLE_CONFIRM_STEP_INVALID); +} + diff --git a/src/signTxOutput_ui.h b/src/signTxOutput_ui.h new file mode 100644 index 00000000..8c75f379 --- /dev/null +++ b/src/signTxOutput_ui.h @@ -0,0 +1,93 @@ +#ifndef H_CARDANO_APP_SIGN_TX_OUTPUT_UI +#define H_CARDANO_APP_SIGN_TX_OUTPUT_UI +#endif // H_CARDANO_APP_SIGN_TX_OUTPUT_UI + +#ifdef HAVE_BAGL +#include "uiScreens_bagl.h" +#elif defined(HAVE_NBGL) +#include "uiScreens_nbgl.h" +#endif + +// ============================== TOP LEVEL DATA ============================== + +enum { + HANDLE_OUTPUT_ADDRESS_BYTES_STEP_WARNING_DATUM = 3100, + HANDLE_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADDRESS, + HANDLE_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADA_AMOUNT, + HANDLE_OUTPUT_ADDRESS_BYTES_STEP_RESPOND, + HANDLE_OUTPUT_ADDRESS_BYTES_STEP_INVALID, +}; + +void signTx_handleOutput_address_bytes_ui_runStep(); + +enum { + HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_BEGIN = 3200, + HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_WARNING_DATUM, + HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_SPENDING_PATH, + HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_STAKING_INFO, + HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS, + HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_AMOUNT, + HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_RESPOND, + HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_INVALID, +}; + +void signTx_handleOutput_addressParams_ui_runStep(); + +enum { + HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_INTRO = 3300, + HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADDRESS, + HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADA_AMOUNT, + HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_RESPOND, + HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_INVALID, +}; + +void signTx_handleCollateralOutput_addressBytes_ui_runStep(); + +// ============================== TOKEN ============================== + +enum { + HANDLE_TOKEN_STEP_DISPLAY_NAME = 3400, + HANDLE_TOKEN_STEP_DISPLAY_AMOUNT, + HANDLE_TOKEN_STEP_RESPOND, + HANDLE_TOKEN_STEP_INVALID, +}; + +void handleToken_ui_runStep(); + +// ========================== DATUM ============================= + +enum { + HANDLE_DATUM_HASH_STEP_DISPLAY = 3500, + HANDLE_DATUM_HASH_STEP_RESPOND, + HANDLE_DATUM_HASH_STEP_INVALID, +}; + +void signTxOutput_handleDatumHash_ui_runStep(); + +enum { + HANDLE_DATUM_INLINE_STEP_DISPLAY = 3600, + HANDLE_DATUM_INLINE_STEP_RESPOND, + HANDLE_DATUM_INLINE_STEP_INVALID, +}; + +void signTxOutput_handleDatumInline_ui_runStep(); + +// ========================== REFERENCE SCRIPT ============================= + +enum { + HANDLE_SCRIPT_REF_STEP_DISPLAY = 3700, + HANDLE_SCRIPT_REF_STEP_RESPOND, + HANDLE_SCRIPT_REF_STEP_INVALID, +}; + +void handleRefScript_ui_runStep(); + +// ============================== CONFIRM ============================== + +enum { + HANDLE_CONFIRM_STEP_FINAL_CONFIRM = 3800, + HANDLE_CONFIRM_STEP_RESPOND, + HANDLE_CONFIRM_STEP_INVALID, +}; + +void signTxOutput_handleConfirm_ui_runStep(); From 0986212cd8cde6667019ea252d42fe6721be6113 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 18 Jan 2023 14:13:57 +0100 Subject: [PATCH 024/105] Makefile: remove incompatible-pointer-types errors, because of SDK warnings --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index bbf7614e..68c4b749 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ endif ############## # based in part on https://interrupt.memfault.com/blog/best-and-worst-gcc-clang-compiler-flags -WERROR := -Werror=incompatible-pointer-types -Werror=return-type -Werror=parentheses -Werror=format-security +WERROR := -Werror=return-type -Werror=parentheses -Werror=format-security CC := $(CLANGPATH)clang CFLAGS += -std=gnu99 -Wall -Wextra -Wuninitialized -Wshadow -Wformat=2 -Wwrite-strings -Wundef -fno-common $(WERROR) From 3db49e630833e6ba24e218496f2087d3d221d012 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 6 Mar 2023 14:35:43 +0100 Subject: [PATCH 025/105] assert: display message for nbgl --- src/assert.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/assert.c b/src/assert.c index d7d5d2b4..82caf643 100644 --- a/src/assert.c +++ b/src/assert.c @@ -23,7 +23,11 @@ void assert( { PRINTF("Assertion failed %s\n", msgStr); #ifndef FUZZING + #ifdef HAVE_BAGL ui_displayPaginatedText("Assertion failed", msgStr, NULL); + #elif defined(HAVE_NBGL) + display_prompt("Assertion failed", msgStr, NULL, NULL); + #endif #endif THROW(ERR_ASSERT); } From 22c99802a34d02ce0e2d2119b69d376cb22d2711 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 14 Mar 2023 16:31:06 +0100 Subject: [PATCH 026/105] ci: use reusable workflows --- .github/workflows/ci.yml | 49 +++-------------------- .github/workflows/guidelines_enforcer.yml | 23 +++++++++++ 2 files changed, 28 insertions(+), 44 deletions(-) create mode 100644 .github/workflows/guidelines_enforcer.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f30f9d00..39d7d0ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,47 +10,8 @@ on: workflow_dispatch: jobs: - nano_build: - name: Build application for NanoS, X and S+ - strategy: - matrix: - include: - - SDK: "$NANOS_SDK" - name: nanos - - SDK: "$NANOX_SDK" - name: nanox - - SDK: "$NANOSP_SDK" - name: nanosp - runs-on: ubuntu-latest - container: - image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest - steps: - - name: Clone - uses: actions/checkout@v2 - - name: Build - run: | - make clean - make DEBUG=1 BOLOS_SDK=${{ matrix.SDK }} - mv bin/app.elf bin/cardano_${{ matrix.name }}.elf - - name: Upload app binary - uses: actions/upload-artifact@v2 - with: - name: apps - path: bin/*.elf - - scan-build: - name: Clang Static Analyzer - runs-on: ubuntu-latest - container: - image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest - steps: - - uses: actions/checkout@v2 - - name: Build with Clang Static Analyzer - run: | - make clean - scan-build --use-cc=clang -analyze-headers -enable-checker security -enable-checker unix -enable-checker valist -o scan-build --status-bugs make default - - uses: actions/upload-artifact@v2 - if: failure() - with: - name: scan-build - path: scan-build + build_application: + name: Build application using the reusable workflow + uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_build.yml@v1 + with: + upload_app_binaries_artifact: "compiled_app_binaries" diff --git a/.github/workflows/guidelines_enforcer.yml b/.github/workflows/guidelines_enforcer.yml new file mode 100644 index 00000000..fdaf9f27 --- /dev/null +++ b/.github/workflows/guidelines_enforcer.yml @@ -0,0 +1,23 @@ +name: Ensure compliance with Ledger guidelines + +# This workflow is mandatory in all applications +# It calls a reusable workflow guidelines_enforcer developed by Ledger's internal developer team. +# The successful completion of the reusable workflow is a mandatory step for an app to be available on the Ledger +# application store. +# +# More information on the guidelines can be found in the repository: +# LedgerHQ/ledger-app-workflows/ + +on: + workflow_dispatch: + push: + branches: + - master + - main + - develop + pull_request: + +jobs: + guidelines_enforcer: + name: Call Ledger guidelines_enforcer + uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_guidelines_enforcer.yml@v1 From c14ad0975a6de23217fceceb32831663aebc30e4 Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Tue, 7 Mar 2023 14:51:16 +0100 Subject: [PATCH 027/105] apply astyle formatting --- src/deriveAddress.c | 189 ++++++------- src/deriveNativeScriptHash_ui.c | 188 +++++++------ src/deriveNativeScriptHash_ui.h | 4 +- src/getPublicKeys_ui.c | 144 +++++----- src/io.c | 22 +- src/main.c | 10 +- src/signCVote_ui.c | 108 +++---- src/signOpCert.c | 84 +++--- src/signTx.h | 2 +- src/signTxCVoteRegistration_ui.c | 217 +++++++------- src/signTxMint_ui.c | 44 +-- src/signTxOutput_ui.c | 218 +++++++------- src/signTxOutput_ui.h | 2 +- src/signTxPoolRegistration_ui.c | 426 ++++++++++++++-------------- src/signTxUtils.c | 4 +- src/signTx_ui.c | 470 ++++++++++++++++--------------- src/ui.h | 6 +- src/uiScreens_nbgl.c | 132 ++++----- src/uiScreens_nbgl.h | 20 +- 19 files changed, 1147 insertions(+), 1143 deletions(-) diff --git a/src/deriveAddress.c b/src/deriveAddress.c index 24f3ead0..36dae829 100644 --- a/src/deriveAddress.c +++ b/src/deriveAddress.c @@ -24,12 +24,13 @@ enum { }; -void deriveAddress_response(void) { - ctx->responseReadyMagic = 0; - ASSERT(ctx->address.size <= SIZEOF(ctx->address.buffer)); +void deriveAddress_response(void) +{ + ctx->responseReadyMagic = 0; + ASSERT(ctx->address.size <= SIZEOF(ctx->address.buffer)); - io_send_buf(SUCCESS, ctx->address.buffer, ctx->address.size); - ui_idle(); + io_send_buf(SUCCESS, ctx->address.buffer, ctx->address.size); + ui_idle(); } static void prepareResponse() { @@ -82,77 +83,77 @@ static void deriveAddress_return_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(RETURN_UI_STEP_WARNING) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "Unusual request", "Proceed with care", this_fn ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_warning( - "Unusual request", - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning( + "Unusual request", + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } UI_STEP(RETURN_UI_STEP_BEGIN) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText("Export", "address", this_fn); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_prompt( - "Export address", - "", - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt( + "Export address", + "", + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } UI_STEP(RETURN_UI_STEP_SPENDING_PATH) { if (determineSpendingChoice(ctx->addressParams.type) == SPENDING_NONE) { // reward address UI_STEP_JUMP(RETURN_UI_STEP_STAKING_INFO); } -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displaySpendingInfoScreen(&ctx->addressParams, this_fn); -#elif defined(HAVE_NBGL) + #elif defined(HAVE_NBGL) #define SPENDING_INFO_SIZE MAX(11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX, 2 * BECH32_BUFFER_SIZE_MAX) - char line1[30]; - char spendingInfo[SPENDING_INFO_SIZE] = {0}; + char line1[30]; + char spendingInfo[SPENDING_INFO_SIZE] = {0}; ui_getSpendingInfoScreen(line1, SIZEOF(line1), spendingInfo, SIZEOF(spendingInfo), &ctx->addressParams); - fill_and_display_if_required(line1, spendingInfo, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required(line1, spendingInfo, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(RETURN_UI_STEP_STAKING_INFO) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayStakingInfoScreen(&ctx->addressParams, this_fn); -#elif defined(HAVE_NBGL) - char line1[30] = {0}; - char stakingInfo[120] = {0}; + #elif defined(HAVE_NBGL) + char line1[30] = {0}; + char stakingInfo[120] = {0}; ui_getStakingInfoScreen(line1, SIZEOF(line1), stakingInfo, SIZEOF(stakingInfo), &ctx->addressParams); - fill_and_display_if_required(line1, stakingInfo, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required(line1, stakingInfo, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(RETURN_UI_STEP_CONFIRM) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPrompt( "Confirm", "export address?", this_fn, respond_with_user_reject ); -#elif defined(HAVE_NBGL) - display_confirmation( - "Confirm\n address export", - "", - "ADDRESS\nEXPORTED", - "Address\nrejected", - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_confirmation( + "Confirm\n address export", + "", + "ADDRESS\nEXPORTED", + "Address\nrejected", + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } UI_STEP(RETURN_UI_STEP_RESPOND) { ctx->responseReadyMagic = 0; @@ -206,98 +207,98 @@ static void deriveAddress_display_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(DISPLAY_UI_STEP_WARNING) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "Unusual request", "Proceed with care", this_fn ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_warning( - "Unusual request", - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning( + "Unusual request", + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } UI_STEP(DISPLAY_UI_STEP_INSTRUCTIONS) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "Verify address", "Make sure it agrees with your computer", this_fn ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_warning( - "Make sure address matches\nwith your computer", - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning( + "Make sure address matches\nwith your computer", + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } UI_STEP(DISPLAY_UI_STEP_SPENDING_INFO) { if (determineSpendingChoice(ctx->addressParams.type) == SPENDING_NONE) { // reward address UI_STEP_JUMP(DISPLAY_UI_STEP_STAKING_INFO); } -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displaySpendingInfoScreen(&ctx->addressParams, this_fn); -#elif defined(HAVE_NBGL) + #elif defined(HAVE_NBGL) #define SPENDING_INFO_SIZE MAX(11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX, 2 * BECH32_BUFFER_SIZE_MAX) - char line1[30] = {0}; - char spendingInfo[SPENDING_INFO_SIZE] = {0}; + char line1[30] = {0}; + char spendingInfo[SPENDING_INFO_SIZE] = {0}; ui_getSpendingInfoScreen(line1, SIZEOF(line1), spendingInfo, SIZEOF(spendingInfo), &ctx->addressParams); - fill_address_data(line1, spendingInfo); - UI_STEP_JUMP(DISPLAY_UI_STEP_STAKING_INFO); -#endif // HAVE_BAGL + fill_address_data(line1, spendingInfo); + UI_STEP_JUMP(DISPLAY_UI_STEP_STAKING_INFO); + #endif // HAVE_BAGL } UI_STEP(DISPLAY_UI_STEP_STAKING_INFO) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayStakingInfoScreen(&ctx->addressParams, this_fn); -#elif defined(HAVE_NBGL) - char line1[30] = {0}; - char stakingInfo[120] = {0}; + #elif defined(HAVE_NBGL) + char line1[30] = {0}; + char stakingInfo[120] = {0}; ui_getStakingInfoScreen(line1, SIZEOF(line1), stakingInfo, SIZEOF(stakingInfo), &ctx->addressParams); - fill_address_data(line1, stakingInfo); - UI_STEP_JUMP(DISPLAY_UI_STEP_ADDRESS); -#endif // HAVE_BAGL + fill_address_data(line1, stakingInfo); + UI_STEP_JUMP(DISPLAY_UI_STEP_ADDRESS); + #endif // HAVE_BAGL } UI_STEP(DISPLAY_UI_STEP_ADDRESS) { ASSERT(ctx->address.size <= SIZEOF(ctx->address.buffer)); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayAddressScreen( "Address", ctx->address.buffer, ctx->address.size, this_fn ); -#elif defined(HAVE_NBGL) - char humanAddress[MAX_HUMAN_ADDRESS_SIZE] = {0}; + #elif defined(HAVE_NBGL) + char humanAddress[MAX_HUMAN_ADDRESS_SIZE] = {0}; ui_getAddressScreen( - humanAddress, - SIZEOF(humanAddress), + humanAddress, + SIZEOF(humanAddress), ctx->address.buffer, ctx->address.size ); - fill_address_data((char*)"Address", humanAddress); - UI_STEP_JUMP(DISPLAY_UI_STEP_CONFIRM) -#endif // HAVE_BAGL + fill_address_data((char*)"Address", humanAddress); + UI_STEP_JUMP(DISPLAY_UI_STEP_CONFIRM) + #endif // HAVE_BAGL } UI_STEP(DISPLAY_UI_STEP_CONFIRM) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPrompt( "Confirm", "address?", this_fn, respond_with_user_reject ); -#elif defined(HAVE_NBGL) - display_address( - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_address( + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } UI_STEP(DISPLAY_UI_STEP_RESPOND) { io_send_buf(SUCCESS, NULL, 0); diff --git a/src/deriveNativeScriptHash_ui.c b/src/deriveNativeScriptHash_ui.c index 295c0ccb..b07631b3 100644 --- a/src/deriveNativeScriptHash_ui.c +++ b/src/deriveNativeScriptHash_ui.c @@ -69,28 +69,29 @@ static void deriveScriptHash_display_ui_position(uint8_t level, ui_callback_fn_t VALIDATE(uiPaginatedText_canFitStringIntoFullText(positionDescription), ERR_INVALID_DATA); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( HEADER, positionDescription, callback ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - fill_and_display_new_page(HEADER, positionDescription, callback, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + fill_and_display_new_page(HEADER, positionDescription, callback, respond_with_user_reject); + #endif // HAVE_BAGL } #ifdef HAVE_NBGL -static void deriveScriptHash_display_ui_runStep_cb(void) { - // max possible length 85: "Requires n out of k signatures. Contains k nested scripts." - // where n and k is 2^32-1 - char text[87] = {0}; - explicit_bzero(text, SIZEOF(text)); - snprintf(text, SIZEOF(text), "%u nested scripts", ctx->complexScripts[ctx->level].remainingScripts); - // make sure all the information is displayed to the user - ASSERT(strlen(text) + 1 < SIZEOF(text)); - fill_and_display_if_required("Script contents", text, deriveScriptHash_display_ui_runStep, respond_with_user_reject); +static void deriveScriptHash_display_ui_runStep_cb(void) +{ + // max possible length 85: "Requires n out of k signatures. Contains k nested scripts." + // where n and k is 2^32-1 + char text[87] = {0}; + explicit_bzero(text, SIZEOF(text)); + snprintf(text, SIZEOF(text), "%u nested scripts", ctx->complexScripts[ctx->level].remainingScripts); + // make sure all the information is displayed to the user + ASSERT(strlen(text) + 1 < SIZEOF(text)); + fill_and_display_if_required("Script contents", text, deriveScriptHash_display_ui_runStep, respond_with_user_reject); } #endif // HAVE_NBGL @@ -113,63 +114,63 @@ void deriveScriptHash_display_ui_runStep() } } - UI_STEP(DISPLAY_UI_STEP_TITLE) { -#ifdef HAVE_BAGL - UI_STEP_JUMP(DISPLAY_UI_STEP_SCRIPT_CONTENT); -#elif defined(HAVE_NBGL) - display_prompt("Review Script", "", this_fn, respond_with_user_reject); -#endif // HAVE_NBGL - } -#ifdef HAVE_NBGL + UI_STEP(DISPLAY_UI_STEP_TITLE) { + #ifdef HAVE_BAGL + UI_STEP_JUMP(DISPLAY_UI_STEP_SCRIPT_CONTENT); + #elif defined(HAVE_NBGL) + display_prompt("Review Script", "", this_fn, respond_with_user_reject); + #endif // HAVE_NBGL + } + #ifdef HAVE_NBGL UI_STEP(DISPLAY_UI_STEP_SCRIPT_TYPE) { - set_light_confirmation(true); + set_light_confirmation(true); switch (ctx->ui_scriptType) { - case UI_SCRIPT_PUBKEY_PATH: - fill_and_display_if_required("Script type", "Pubkey path", this_fn, respond_with_user_reject); + case UI_SCRIPT_PUBKEY_PATH: + fill_and_display_if_required("Script type", "Pubkey path", this_fn, respond_with_user_reject); break; - case UI_SCRIPT_PUBKEY_HASH: - fill_and_display_if_required("Script type", "Pubkey hash", this_fn, respond_with_user_reject); + case UI_SCRIPT_PUBKEY_HASH: + fill_and_display_if_required("Script type", "Pubkey hash", this_fn, respond_with_user_reject); break; case UI_SCRIPT_ALL: - fill_and_display_if_required("Script type", "ALL", this_fn, respond_with_user_reject); + fill_and_display_if_required("Script type", "ALL", this_fn, respond_with_user_reject); break; - case UI_SCRIPT_ANY: - fill_and_display_if_required("Script type", "ANY", this_fn, respond_with_user_reject); + case UI_SCRIPT_ANY: + fill_and_display_if_required("Script type", "ANY", this_fn, respond_with_user_reject); break; - case UI_SCRIPT_N_OF_K: - fill_and_display_if_required("Script type", "N out K", this_fn, respond_with_user_reject); + case UI_SCRIPT_N_OF_K: + fill_and_display_if_required("Script type", "N out K", this_fn, respond_with_user_reject); break; - case UI_SCRIPT_INVALID_BEFORE: - fill_and_display_if_required("Script type", "Invalid before", this_fn, respond_with_user_reject); + case UI_SCRIPT_INVALID_BEFORE: + fill_and_display_if_required("Script type", "Invalid before", this_fn, respond_with_user_reject); break; - case UI_SCRIPT_INVALID_HEREAFTER: - fill_and_display_if_required("Script type", "Invalid hereafter", this_fn, respond_with_user_reject); + case UI_SCRIPT_INVALID_HEREAFTER: + fill_and_display_if_required("Script type", "Invalid hereafter", this_fn, respond_with_user_reject); break; default: THROW(ERR_INVALID_STATE); } - } -#endif // HAVE_NBGL + } + #endif // HAVE_NBGL UI_STEP(DISPLAY_UI_STEP_SCRIPT_CONTENT) { TRACE("ui_scriptType = %d", ctx->ui_scriptType); switch (ctx->ui_scriptType) { case UI_SCRIPT_PUBKEY_PATH: { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPathScreen( HEADER, &ctx->scriptContent.pubkeyPath, this_fn ); -#elif defined(HAVE_NBGL) - char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; - ui_getPathScreen(pathStr, SIZEOF(pathStr), &ctx->scriptContent.pubkeyPath); - fill_and_display_if_required("Pubkey path", pathStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; + ui_getPathScreen(pathStr, SIZEOF(pathStr), &ctx->scriptContent.pubkeyPath); + fill_and_display_if_required("Pubkey path", pathStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL break; } case UI_SCRIPT_PUBKEY_HASH: { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayBech32Screen( HEADER, "addr_shared_vkh", @@ -177,11 +178,11 @@ void deriveScriptHash_display_ui_runStep() ADDRESS_KEY_HASH_LENGTH, this_fn ); -#elif defined(HAVE_NBGL) - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; - ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "addr_shared_vkh", ctx->scriptContent.pubkeyHash, ADDRESS_KEY_HASH_LENGTH); - fill_and_display_if_required("Pubkey hash", encodedStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "addr_shared_vkh", ctx->scriptContent.pubkeyHash, ADDRESS_KEY_HASH_LENGTH); + fill_and_display_if_required("Pubkey hash", encodedStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL break; } case UI_SCRIPT_ALL: @@ -192,7 +193,7 @@ void deriveScriptHash_display_ui_runStep() explicit_bzero(text, SIZEOF(text)); STATIC_ASSERT(sizeof(ctx->complexScripts[ctx->level].remainingScripts) <= sizeof(unsigned), "oversized type for %u"); STATIC_ASSERT(!IS_SIGNED(ctx->complexScripts[ctx->level].remainingScripts), "signed type for %u"); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL snprintf(text, SIZEOF(text), "Contains %u nested scripts.", ctx->complexScripts[ctx->level].remainingScripts); // make sure all the information is displayed to the user ASSERT(strlen(text) + 1 < SIZEOF(text)); @@ -202,12 +203,12 @@ void deriveScriptHash_display_ui_runStep() text, this_fn ); -#elif defined(HAVE_NBGL) + #elif defined(HAVE_NBGL) snprintf(text, SIZEOF(text), "%u nested scripts", ctx->complexScripts[ctx->level].remainingScripts); // make sure all the information is displayed to the user ASSERT(strlen(text) + 1 < SIZEOF(text)); - fill_and_display_if_required("Content", text, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required("Content", text, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL break; } case UI_SCRIPT_N_OF_K: { @@ -218,7 +219,7 @@ void deriveScriptHash_display_ui_runStep() // max possible length 85: "Requires n out of k signatures. Contains k nested scripts." // where n and k is 2^32-1 char text[87] = {0}; -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL explicit_bzero(text, SIZEOF(text)); snprintf(text, SIZEOF(text), "Requires %u out of %u signatures. Contains %u nested scripts", ctx->scriptContent.requiredScripts, ctx->complexScripts[ctx->level].remainingScripts, ctx->complexScripts[ctx->level].remainingScripts); // make sure all the information is displayed to the user @@ -229,50 +230,50 @@ void deriveScriptHash_display_ui_runStep() text, this_fn ); -#elif defined(HAVE_NBGL) + #elif defined(HAVE_NBGL) explicit_bzero(text, SIZEOF(text)); snprintf(text, SIZEOF(text), "%u out of %u signatures", ctx->scriptContent.requiredScripts, ctx->complexScripts[ctx->level].remainingScripts); // make sure all the information is displayed to the user ASSERT(strlen(text) + 1 < SIZEOF(text)); - fill_and_display_if_required("Requirement", text, deriveScriptHash_display_ui_runStep_cb, respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required("Requirement", text, deriveScriptHash_display_ui_runStep_cb, respond_with_user_reject); + #endif // HAVE_BAGL break; } case UI_SCRIPT_INVALID_BEFORE: { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayUint64Screen( HEADER, ctx->scriptContent.timelock, this_fn ); -#elif defined(HAVE_NBGL) - char line[30]; - ui_getUint64Screen( - line, - SIZEOF(line), + #elif defined(HAVE_NBGL) + char line[30]; + ui_getUint64Screen( + line, + SIZEOF(line), ctx->scriptContent.timelock - ); - fill_and_display_if_required("Invalid before", line, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL - break; + ); + fill_and_display_if_required("Invalid before", line, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL + break; } case UI_SCRIPT_INVALID_HEREAFTER: { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayUint64Screen( HEADER, ctx->scriptContent.timelock, this_fn ); -#elif defined(HAVE_NBGL) - char line[30]; - ui_getUint64Screen( - line, - SIZEOF(line), + #elif defined(HAVE_NBGL) + char line[30]; + ui_getUint64Screen( + line, + SIZEOF(line), ctx->scriptContent.timelock - ); - fill_and_display_if_required("Invalid hereafter", line, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + ); + fill_and_display_if_required("Invalid hereafter", line, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL break; } default: @@ -282,9 +283,9 @@ void deriveScriptHash_display_ui_runStep() UI_STEP(DISPLAY_UI_STEP_RESPOND) { io_send_buf(SUCCESS, NULL, 0); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayBusy(); // displays dots, called only after I/O to avoid freezing -#endif // HAVE_BAGL + #endif // HAVE_BAGL } UI_STEP_END(DISPLAY_UI_STEP_INVALID); @@ -298,14 +299,15 @@ void deriveNativeScriptHash_displayNativeScriptHash_callback() } #ifdef HAVE_NBGL -static void deriveNativeScriptHash_displayNativeScriptHash_finish(void) { - display_confirmation("Confirm script", "", "SCRIPT\nCONFIRMED", "Script\nrejected", deriveNativeScriptHash_displayNativeScriptHash_callback, respond_with_user_reject); +static void deriveNativeScriptHash_displayNativeScriptHash_finish(void) +{ + display_confirmation("Confirm script", "", "SCRIPT\nCONFIRMED", "Script\nrejected", deriveNativeScriptHash_displayNativeScriptHash_callback, respond_with_user_reject); } #endif // HAVE_NBGL void deriveNativeScriptHash_displayNativeScriptHash_bech32() { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayBech32Screen( "Script hash", "script", @@ -313,25 +315,25 @@ void deriveNativeScriptHash_displayNativeScriptHash_bech32() SCRIPT_HASH_LENGTH, deriveNativeScriptHash_displayNativeScriptHash_callback ); -#elif defined(HAVE_NBGL) - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; - ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "script", ctx->scriptHashBuffer, SCRIPT_HASH_LENGTH); - fill_and_display_if_required("Script hash", encodedStr, deriveNativeScriptHash_displayNativeScriptHash_finish, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "script", ctx->scriptHashBuffer, SCRIPT_HASH_LENGTH); + fill_and_display_if_required("Script hash", encodedStr, deriveNativeScriptHash_displayNativeScriptHash_finish, respond_with_user_reject); + #endif // HAVE_BAGL } void deriveNativeScriptHash_displayNativeScriptHash_policyId() { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayHexBufferScreen( "Policy ID", ctx->scriptHashBuffer, SCRIPT_HASH_LENGTH, deriveNativeScriptHash_displayNativeScriptHash_callback ); -#elif defined(HAVE_NBGL) - char bufferHex[2 * 32 + 1] = {0}; - ui_getHexBufferScreen(bufferHex, SIZEOF(bufferHex), ctx->scriptHashBuffer, SCRIPT_HASH_LENGTH); - fill_and_display_if_required("Policy ID", bufferHex, deriveNativeScriptHash_displayNativeScriptHash_finish, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char bufferHex[2 * 32 + 1] = {0}; + ui_getHexBufferScreen(bufferHex, SIZEOF(bufferHex), ctx->scriptHashBuffer, SCRIPT_HASH_LENGTH); + fill_and_display_if_required("Policy ID", bufferHex, deriveNativeScriptHash_displayNativeScriptHash_finish, respond_with_user_reject); + #endif // HAVE_BAGL } diff --git a/src/deriveNativeScriptHash_ui.h b/src/deriveNativeScriptHash_ui.h index b5e51fbf..1495748c 100644 --- a/src/deriveNativeScriptHash_ui.h +++ b/src/deriveNativeScriptHash_ui.h @@ -3,9 +3,9 @@ enum { DISPLAY_UI_STEP_POSITION = 200, DISPLAY_UI_STEP_TITLE, -#ifdef HAVE_NBGL + #ifdef HAVE_NBGL DISPLAY_UI_STEP_SCRIPT_TYPE, -#endif // HAVE_NBGL + #endif // HAVE_NBGL DISPLAY_UI_STEP_SCRIPT_CONTENT, DISPLAY_UI_STEP_RESPOND, DISPLAY_UI_STEP_INVALID diff --git a/src/getPublicKeys_ui.c b/src/getPublicKeys_ui.c index aae00f82..07f65fd3 100644 --- a/src/getPublicKeys_ui.c +++ b/src/getPublicKeys_ui.c @@ -51,15 +51,16 @@ static void advanceStage() // ============================== derivation and UI state machine for one key ============================== #ifdef HAVE_NBGL -static void getPublicKeys_respondOneKey_ui_cb(void) { - char line1[30] = {0}; - char pathStr[MAX(160,BIP44_PATH_STRING_SIZE_MAX + 1)] = {0}; - ui_getPublicKeyPathScreen( - line1, SIZEOF(line1), - pathStr, SIZEOF(pathStr), - &ctx->pathSpec - ); - fill_and_display_if_required(line1, pathStr, getPublicKeys_respondOneKey_ui_runStep, respond_with_user_reject); +static void getPublicKeys_respondOneKey_ui_cb(void) +{ + char line1[30] = {0}; + char pathStr[MAX(160, BIP44_PATH_STRING_SIZE_MAX + 1)] = {0}; + ui_getPublicKeyPathScreen( + line1, SIZEOF(line1), + pathStr, SIZEOF(pathStr), + &ctx->pathSpec + ); + fill_and_display_if_required(line1, pathStr, getPublicKeys_respondOneKey_ui_runStep, respond_with_user_reject); } #endif // HAVE_NBGL @@ -70,83 +71,82 @@ void getPublicKeys_respondOneKey_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(GET_KEY_UI_STEP_WARNING) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "Unusual request", "Proceed with care", this_fn ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_warning( - "Unusual request", - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning( + "Unusual request", + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL + } + UI_STEP(GET_KEY_UI_STEP_PROMPT) { + #ifdef HAVE_BAGL + UI_STEP_JUMP(GET_KEY_UI_STEP_DISPLAY) + #elif defined(HAVE_NBGL) + display_prompt( + "Export public key", + "", + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } - UI_STEP(GET_KEY_UI_STEP_PROMPT) { -#ifdef HAVE_BAGL - UI_STEP_JUMP(GET_KEY_UI_STEP_DISPLAY) -#elif defined(HAVE_NBGL) - display_prompt( - "Export public key", - "", - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL - } UI_STEP(GET_KEY_UI_STEP_DISPLAY) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayGetPublicKeyPathScreen(&ctx->pathSpec, this_fn); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - bool showAccountDescription = (bip44_classifyPath(&ctx->pathSpec) == PATH_ORDINARY_ACCOUNT); - if (showAccountDescription) { - char line1[30]; - char line2[30]; - ui_getAccountScreeen( - line1, - SIZEOF(line1), - line2, - SIZEOF(line2), - &ctx->pathSpec - ); - fill_and_display_if_required(line1, line2, getPublicKeys_respondOneKey_ui_cb, respond_with_user_reject); - } - else { - getPublicKeys_respondOneKey_ui_cb(); - } -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + bool showAccountDescription = (bip44_classifyPath(&ctx->pathSpec) == PATH_ORDINARY_ACCOUNT); + if (showAccountDescription) { + char line1[30]; + char line2[30]; + ui_getAccountScreeen( + line1, + SIZEOF(line1), + line2, + SIZEOF(line2), + &ctx->pathSpec + ); + fill_and_display_if_required(line1, line2, getPublicKeys_respondOneKey_ui_cb, respond_with_user_reject); + } else { + getPublicKeys_respondOneKey_ui_cb(); + } + #endif // HAVE_BAGL } UI_STEP(GET_KEY_UI_STEP_CONFIRM) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPrompt( "Confirm export", "public key?", this_fn, respond_with_user_reject ); -#elif defined(HAVE_NBGL) - display_confirmation( - "Confirm\npublic key export", - "", - "PUBLIC KEY\nEXPORTED", - "Public key\nrejected", - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_confirmation( + "Confirm\npublic key export", + "", + "PUBLIC KEY\nEXPORTED", + "Public key\nrejected", + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } UI_STEP(GET_KEY_UI_STEP_RESPOND) { ASSERT(ctx->responseReadyMagic == RESPONSE_READY_MAGIC); io_send_buf(SUCCESS, (uint8_t*) &ctx->extPubKey, SIZEOF(ctx->extPubKey)); ctx->responseReadyMagic = 0; // just for safety -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayBusy(); // needs to happen after I/O -#endif // HAVE_BAGL + #endif // HAVE_BAGL ctx->currentPath++; TRACE("Current path: %u / %u", ctx->currentPath, ctx->numPaths); @@ -174,7 +174,7 @@ void getPublicKeys_handleInit_ui_runStep() // make sure all the information is displayed to the user ASSERT(strlen(secondLine) + 1 < SIZEOF(secondLine)); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPrompt( "Confirm export", secondLine, @@ -182,15 +182,15 @@ void getPublicKeys_handleInit_ui_runStep() respond_with_user_reject ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_prompt( - "Review export", + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt( + "Review export", secondLine, - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } UI_STEP(HANDLE_INIT_UI_STEP_RESPOND) { ctx->ui_step = UI_STEP_NONE; // we are finished with this UI state machine diff --git a/src/io.c b/src/io.c index bd6fd860..b78d7ba4 100644 --- a/src/io.c +++ b/src/io.c @@ -84,14 +84,11 @@ unsigned char io_event(unsigned char channel MARK_UNUSED) { // can't have more than one tag in the reply, not supported yet. switch (G_io_seproxyhal_spi_buffer[0]) { - case SEPROXYHAL_TAG_FINGER_EVENT: - UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); - break; case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); -#endif + #endif break; case SEPROXYHAL_TAG_STATUS_EVENT: @@ -100,17 +97,20 @@ unsigned char io_event(unsigned char channel MARK_UNUSED) SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) { THROW(EXCEPTION_IO_RESET); } - UX_DEFAULT_EVENT(); - break; case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL UX_DISPLAYED_EVENT({}); -#endif + #endif + #ifdef HAVE_NBGL + UX_DEFAULT_EVENT(); + #endif + break; #ifdef HAVE_NBGL - UX_DEFAULT_EVENT(); -#endif + case SEPROXYHAL_TAG_FINGER_EVENT: + UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); break; +#endif // HAVE_NBGL case SEPROXYHAL_TAG_TICKER_EVENT: UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, { diff --git a/src/main.c b/src/main.c index 18f05d62..a71d7132 100644 --- a/src/main.c +++ b/src/main.c @@ -157,12 +157,12 @@ static void cardano_main(void) if (e >= _ERR_AUTORESPOND_START && e < _ERR_AUTORESPOND_END) { io_send_buf(e, NULL, 0); flags = IO_ASYNCH_REPLY; -#ifdef HAVE_NBGL + #ifdef HAVE_NBGL if (e != ERR_REJECTED_BY_USER) { - ui_idle(); - display_error(); + ui_idle(); + display_error(); } -#endif + #endif } else { PRINTF("Uncaught error 0x%x", (unsigned) e); #ifdef RESET_ON_CRASH @@ -204,9 +204,7 @@ __attribute__((section(".boot"))) int main(void) __asm volatile("cpsie i"); for (;;) { -#ifdef HAVE_BAGL UX_INIT(); -#endif // HAVE_BAGL os_boot(); BEGIN_TRY { TRY { diff --git a/src/signCVote_ui.c b/src/signCVote_ui.c index b4a1d912..3ed67bdd 100644 --- a/src/signCVote_ui.c +++ b/src/signCVote_ui.c @@ -24,64 +24,64 @@ void handleInit_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(HANDLE_INIT_CONFIRM_START) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPrompt( "Start new", "vote? (CIP-36)", this_fn, respond_with_user_reject ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_prompt("Start new\nvote? (CIP-36)", "", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt("Start new\nvote? (CIP-36)", "", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_INIT_VOTE_PLAN_ID) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayHexBufferScreen( "Vote plan id", ctx->votePlanId, SIZEOF(ctx->votePlanId), this_fn ); -#elif defined(HAVE_NBGL) - char bufferHex[2 * 32 + 1] = {0}; - ui_getHexBufferScreen(bufferHex, SIZEOF(bufferHex), ctx->votePlanId, SIZEOF(ctx->votePlanId)); - fill_and_display_if_required("Vote plan id", bufferHex, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char bufferHex[2 * 32 + 1] = {0}; + ui_getHexBufferScreen(bufferHex, SIZEOF(bufferHex), ctx->votePlanId, SIZEOF(ctx->votePlanId)); + fill_and_display_if_required("Vote plan id", bufferHex, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_INIT_PROPOSAL_INDEX) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayUint64Screen( "Proposal index", ctx->proposalIndex, this_fn ); -#elif defined(HAVE_NBGL) - char line[30]; + #elif defined(HAVE_NBGL) + char line[30]; ui_getUint64Screen( - line, - SIZEOF(line), + line, + SIZEOF(line), ctx->proposalIndex ); - fill_and_display_if_required("Proposal index", line, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required("Proposal index", line, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_INIT_PAYLOAD_TYPE_TAG) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayUint64Screen( "Payload type tag", ctx->payloadTypeTag, this_fn ); -#elif defined(HAVE_NBGL) - char line[30]; + #elif defined(HAVE_NBGL) + char line[30]; ui_getUint64Screen( - line, - SIZEOF(line), + line, + SIZEOF(line), ctx->payloadTypeTag ); - fill_and_display_if_required("Payload type tag", line, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required("Payload type tag", line, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_INIT_RESPOND) { respondSuccessEmptyMsg(); @@ -101,22 +101,22 @@ void handleConfirm_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPrompt( "Confirm", "vote?", this_fn, respond_with_user_reject ); -#elif defined(HAVE_NBGL) - display_confirmation("Confirm\nvote", "", "VOTE\nCONFIRMED", "Vote\nrejected", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_confirmation("Confirm\nvote", "", "VOTE\nCONFIRMED", "Vote\nrejected", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { io_send_buf(SUCCESS, ctx->votecastHash, SIZEOF(ctx->votecastHash)); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayBusy(); // displays dots, called only after I/O to avoid freezing -#endif // HAVE_BAGL + #endif // HAVE_BAGL vote_advanceStage(); } @@ -141,53 +141,53 @@ void handleWitness_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(HANDLE_WITNESS_STEP_WARNING) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "WARNING:", "unusual witness requested", this_fn ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_warning("Unusual\nwitness requested", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning("Unusual\nwitness requested", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_WITNESS_STEP_PROMPT) { -#ifdef HAVE_BAGL - UI_STEP_JUMP(HANDLE_WITNESS_STEP_DISPLAY) -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_prompt("Review witness", "", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #ifdef HAVE_BAGL + UI_STEP_JUMP(HANDLE_WITNESS_STEP_DISPLAY) + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt("Review witness", "", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_WITNESS_STEP_DISPLAY) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPathScreen("Witness path", &ctx->witnessData.path, this_fn); -#elif defined(HAVE_NBGL) - char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; - ui_getPathScreen(pathStr, SIZEOF(pathStr), &ctx->witnessData.path); - fill_and_display_if_required("Witness path", pathStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; + ui_getPathScreen(pathStr, SIZEOF(pathStr), &ctx->witnessData.path); + fill_and_display_if_required("Witness path", pathStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_WITNESS_STEP_CONFIRM) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPrompt( "Sign using", "this witness?", this_fn, _wipeWitnessSignature ); -#elif defined(HAVE_NBGL) - display_confirmation("Sign\nusing witness", "", "WITNESS\nCONFIRMED", "Witness\nrejected", this_fn, _wipeWitnessSignature); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_confirmation("Sign\nusing witness", "", "WITNESS\nCONFIRMED", "Witness\nrejected", this_fn, _wipeWitnessSignature); + #endif // HAVE_BAGL } UI_STEP(HANDLE_WITNESS_STEP_RESPOND) { TRACE("Sending witness data"); TRACE_BUFFER(ctx->witnessData.signature, SIZEOF(ctx->witnessData.signature)); io_send_buf(SUCCESS, ctx->witnessData.signature, SIZEOF(ctx->witnessData.signature)); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayBusy(); // displays dots, called only after I/O to avoid freezing -#endif // HAVE_BAGL + #endif // HAVE_BAGL vote_advanceStage(); } diff --git a/src/signOpCert.c b/src/signOpCert.c index 5ac2e9be..ee108419 100644 --- a/src/signOpCert.c +++ b/src/signOpCert.c @@ -135,116 +135,116 @@ static void signOpCert_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(UI_STEP_WARNING) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "Unusual request", "Proceed with care", this_fn ); -#elif defined(HAVE_NBGL) - display_warning( - "Unusual request", - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_warning( + "Unusual request", + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } UI_STEP(UI_STEP_CONFIRM_START) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPrompt( "Start new", "operational certificate?", this_fn, respond_with_user_reject ); -#elif defined(HAVE_NBGL) + #elif defined(HAVE_NBGL) display_prompt( "Start new\noperational certificate", - "", + "", this_fn, respond_with_user_reject ); -#endif // HAVE_BAGL + #endif // HAVE_BAGL } UI_STEP(UI_STEP_DISPLAY_POOL_COLD_KEY_PATH) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPathScreen("Pool cold key path", &ctx->poolColdKeyPathSpec, this_fn); -#elif defined(HAVE_NBGL) - char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; - ui_getPathScreen(pathStr, SIZEOF(pathStr), &ctx->poolColdKeyPathSpec); - fill_and_display_if_required("Pool cold key path", pathStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; + ui_getPathScreen(pathStr, SIZEOF(pathStr), &ctx->poolColdKeyPathSpec); + fill_and_display_if_required("Pool cold key path", pathStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(UI_STEP_DISPLAY_POOL_ID) { uint8_t poolKeyHash[POOL_KEY_HASH_LENGTH] = {0}; bip44_pathToKeyHash(&ctx->poolColdKeyPathSpec, poolKeyHash, SIZEOF(poolKeyHash)); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayBech32Screen( "Pool ID", "pool", poolKeyHash, SIZEOF(poolKeyHash), this_fn ); -#elif defined(HAVE_NBGL) - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; - ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "pool", poolKeyHash, SIZEOF(poolKeyHash)); - fill_and_display_if_required("Pool ID", encodedStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "pool", poolKeyHash, SIZEOF(poolKeyHash)); + fill_and_display_if_required("Pool ID", encodedStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(UI_STEP_DISPLAY_KES_PUBLIC_KEY) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayBech32Screen( "KES public key", "kes_vk", ctx->kesPublicKey, SIZEOF(ctx->kesPublicKey), this_fn ); -#elif defined(HAVE_NBGL) - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; - ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "kes_vk", ctx->kesPublicKey, SIZEOF(ctx->kesPublicKey)); - fill_and_display_if_required("KES public key", encodedStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "kes_vk", ctx->kesPublicKey, SIZEOF(ctx->kesPublicKey)); + fill_and_display_if_required("KES public key", encodedStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(UI_STEP_DISPLAY_KES_PERIOD) { char kesPeriodString[50] = {0}; explicit_bzero(kesPeriodString, SIZEOF(kesPeriodString)); str_formatUint64(ctx->kesPeriod, kesPeriodString, SIZEOF(kesPeriodString)); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "KES period", kesPeriodString, this_fn ); -#elif defined(HAVE_NBGL) - fill_and_display_if_required("KES period", kesPeriodString, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + fill_and_display_if_required("KES period", kesPeriodString, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(UI_STEP_DISPLAY_ISSUE_COUNTER) { char issueCounterString[50] = {0}; explicit_bzero(issueCounterString, SIZEOF(issueCounterString)); str_formatUint64(ctx->issueCounter, issueCounterString, SIZEOF(issueCounterString)); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "Issue counter", issueCounterString, this_fn ); -#elif defined(HAVE_NBGL) - fill_and_display_if_required("Issue counter", issueCounterString, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + fill_and_display_if_required("Issue counter", issueCounterString, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(UI_STEP_CONFIRM) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPrompt( "Confirm", "operational certificate?", this_fn, respond_with_user_reject ); -#elif defined(HAVE_NBGL) - display_confirmation("Confirm\n operation certificate", "", "OP CERTIFICATE\nCONFIRMED", "Op certificate\nrejected", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_confirmation("Confirm\n operation certificate", "", "OP CERTIFICATE\nCONFIRMED", "Op certificate\nrejected", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(UI_STEP_RESPOND) { ASSERT(ctx->responseReadyMagic == RESPONSE_READY_MAGIC); diff --git a/src/signTx.h b/src/signTx.h index 288bfccc..cfcd50c0 100644 --- a/src/signTx.h +++ b/src/signTx.h @@ -252,7 +252,7 @@ static inline bool signTx_parseIncluded(uint8_t value) } } -// advances the stage of the main state machine +// advances the stage of the main state machine void tx_advanceStage(void); #endif // H_CARDANO_APP_SIGN_TX diff --git a/src/signTxCVoteRegistration_ui.c b/src/signTxCVoteRegistration_ui.c index 5c420170..468d6d89 100644 --- a/src/signTxCVoteRegistration_ui.c +++ b/src/signTxCVoteRegistration_ui.c @@ -24,34 +24,34 @@ static void _displayVoteKey(ui_callback_fn_t callback) switch (subctx->stateData.delegation.type) { case DELEGATION_KEY: { STATIC_ASSERT(SIZEOF(subctx->stateData.delegation.votePubKey) == CVOTE_PUBLIC_KEY_LENGTH, "wrong vote public key size"); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayBech32Screen( "Vote public key", "cvote_vk", subctx->stateData.delegation.votePubKey, CVOTE_PUBLIC_KEY_LENGTH, callback ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; - ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "cvote_vk", subctx->stateData.delegation.votePubKey, CVOTE_PUBLIC_KEY_LENGTH); - fill_and_display_if_required("Vote public key", encodedStr, callback, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "cvote_vk", subctx->stateData.delegation.votePubKey, CVOTE_PUBLIC_KEY_LENGTH); + fill_and_display_if_required("Vote public key", encodedStr, callback, respond_with_user_reject); + #endif // HAVE_BAGL break; } case DELEGATION_PATH: { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPathScreen( "Vote public key", &subctx->stateData.delegation.votePubKeyPath, callback ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; - ui_getPathScreen(pathStr, SIZEOF(pathStr), &subctx->stateData.delegation.votePubKeyPath); - fill_and_display_if_required("Vote public key", pathStr, callback, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; + ui_getPathScreen(pathStr, SIZEOF(pathStr), &subctx->stateData.delegation.votePubKeyPath); + fill_and_display_if_required("Vote public key", pathStr, callback, respond_with_user_reject); + #endif // HAVE_BAGL break; } default: @@ -69,23 +69,23 @@ void signTxCVoteRegistration_handleVoteKey_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_VOTE_KEY_STEP_WARNING) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "WARNING:", "unusual vote key", this_fn ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_warning("Unusual\nvote key", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning("Unusual\nvote key", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_VOTE_KEY_STEP_DISPLAY) { _displayVoteKey(this_fn); } UI_STEP(HANDLE_VOTE_KEY_STEP_RESPOND) { respondSuccessEmptyMsg(); - voting_registration_advanceState(); + voting_registration_advanceState(); } UI_STEP_END(HANDLE_VOTE_KEY_STEP_INVALID); } @@ -102,37 +102,37 @@ void signTxCVoteRegistration_handleDelegation_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_VOTE_KEY_STEP_WARNING) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "WARNING:", "unusual vote key", this_fn ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_warning("Unusual\nvote key", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning("Unusual\nvote key", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_DELEGATION_STEP_VOTE_KEY) { _displayVoteKey(this_fn); } UI_STEP(HANDLE_DELEGATION_STEP_WEIGHT) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayUint64Screen( "Weight", subctx->stateData.delegation.weight, this_fn ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - char line[30]; + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + char line[30]; ui_getUint64Screen( - line, - SIZEOF(line), + line, + SIZEOF(line), subctx->stateData.delegation.weight ); - fill_and_display_if_required("Weight", line, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required("Weight", line, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_DELEGATION_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -147,16 +147,17 @@ void signTxCVoteRegistration_handleDelegation_ui_runStep() // ============================== STAKING KEY ============================== #ifdef HAVE_NBGL -static void signTxCVoteRegistration_handleStakingKey_ui_cb(void) { +static void signTxCVoteRegistration_handleStakingKey_ui_cb(void) +{ cvote_registration_context_t* subctx = accessSubContext(); - char line1[30] = {0}; - char pathStr[MAX(160,BIP44_PATH_STRING_SIZE_MAX + 1)] = {0}; - ui_getPublicKeyPathScreen( - line1, SIZEOF(line1), - pathStr, SIZEOF(pathStr), - &subctx->stakingKeyPath - ); - fill_and_display_if_required(line1, pathStr, signTxCVoteRegistration_handleStakingKey_ui_runStep, respond_with_user_reject); + char line1[30] = {0}; + char pathStr[MAX(160, BIP44_PATH_STRING_SIZE_MAX + 1)] = {0}; + ui_getPublicKeyPathScreen( + line1, SIZEOF(line1), + pathStr, SIZEOF(pathStr), + &subctx->stakingKeyPath + ); + fill_and_display_if_required(line1, pathStr, signTxCVoteRegistration_handleStakingKey_ui_runStep, respond_with_user_reject); } #endif // HAVE_NBGL @@ -170,39 +171,39 @@ void signTxCVoteRegistration_handleStakingKey_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_STAKING_KEY_STEP_WARNING) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "Unusual request", "Proceed with care", this_fn ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_warning("Unusual request\nProceed with care", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning("Unusual request\nProceed with care", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_STAKING_KEY_STEP_DISPLAY) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayStakingKeyScreen( &subctx->stakingKeyPath, this_fn ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - bool showAccountDescription = bip44_isPathReasonable(&subctx->stakingKeyPath); - if (showAccountDescription) { - char line1[30]; - char line2[30]; - ui_getAccountScreeen( - line1, - SIZEOF(line1), - line2, - SIZEOF(line2), - &subctx->stakingKeyPath - ); - fill_and_display_if_required(line1, line2, signTxCVoteRegistration_handleStakingKey_ui_cb, respond_with_user_reject); - } -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + bool showAccountDescription = bip44_isPathReasonable(&subctx->stakingKeyPath); + if (showAccountDescription) { + char line1[30]; + char line2[30]; + ui_getAccountScreeen( + line1, + SIZEOF(line1), + line2, + SIZEOF(line2), + &subctx->stakingKeyPath + ); + fill_and_display_if_required(line1, line2, signTxCVoteRegistration_handleStakingKey_ui_cb, respond_with_user_reject); + } + #endif // HAVE_BAGL } UI_STEP(HANDLE_STAKING_KEY_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -224,16 +225,16 @@ void signTxCVoteRegistration_handlePaymentAddress_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_WARNING) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "Unusual request", "Proceed with care", this_fn ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_warning("Unusual request\nProceed with care", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning("Unusual request\nProceed with care", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS) { uint8_t addressBuffer[MAX_ADDRESS_SIZE] = {0}; @@ -242,24 +243,24 @@ void signTxCVoteRegistration_handlePaymentAddress_ui_runStep() addressBuffer, SIZEOF(addressBuffer) ); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayAddressScreen( "Rewards go to", addressBuffer, addressSize, this_fn ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - char humanAddress[MAX_HUMAN_ADDRESS_SIZE] = {0}; + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + char humanAddress[MAX_HUMAN_ADDRESS_SIZE] = {0}; ui_getAddressScreen( - humanAddress, - SIZEOF(humanAddress), + humanAddress, + SIZEOF(humanAddress), addressBuffer, addressSize ); - fill_and_display_if_required("Rewards go to", humanAddress, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required("Rewards go to", humanAddress, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -280,21 +281,21 @@ void signTxCVoteRegistration_handleNonce_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_NONCE_STEP_DISPLAY) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayUint64Screen( "Nonce", subctx->stateData.nonce, this_fn ); -#elif defined(HAVE_NBGL) - char line[30]; + #elif defined(HAVE_NBGL) + char line[30]; ui_getUint64Screen( - line, - SIZEOF(line), + line, + SIZEOF(line), subctx->stateData.nonce ); - fill_and_display_if_required("Nonce", line, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required("Nonce", line, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_NONCE_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -315,21 +316,21 @@ void signTxCVoteRegistration_handleVotingPurpose_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_VOTING_PURPOSE_STEP_DISPLAY) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayUint64Screen( "Voting purpose", subctx->stateData.votingPurpose, this_fn ); -#elif defined(HAVE_NBGL) - char line[30]; + #elif defined(HAVE_NBGL) + char line[30]; ui_getUint64Screen( - line, - SIZEOF(line), + line, + SIZEOF(line), subctx->stateData.votingPurpose ); - fill_and_display_if_required("Voting purpose", line, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required("Voting purpose", line, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_VOTING_PURPOSE_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -351,40 +352,40 @@ void signTxCVoteRegistration_handleConfirm_ui_runStep() UI_STEP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM) { // confirming this means the signature being sent out of the device // so we want to show it in non-expert mode too -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPrompt( "Confirm vote key", "registration?", this_fn, respond_with_user_reject ); -#elif defined(HAVE_NBGL) - display_confirmation( - "Confirm vote key\nregistration", - "", - "VOTE KEY\nCONFIRMED", - "Vote key\nrejected", - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_confirmation( + "Confirm vote key\nregistration", + "", + "VOTE KEY\nCONFIRMED", + "Vote key\nrejected", + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } UI_STEP(HANDLE_CONFIRM_STEP_DISPLAY_HASH) { if (!app_mode_expert()) { UI_STEP_JUMP(HANDLE_CONFIRM_STEP_RESPOND); } -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayHexBufferScreen( "Auxiliary data hash", subctx->auxDataHash, SIZEOF(subctx->auxDataHash), this_fn ); -#elif defined(HAVE_NBGL) - char bufferHex[2 * 32 + 1] = {0}; - ui_getHexBufferScreen(bufferHex, SIZEOF(bufferHex), subctx->auxDataHash, SIZEOF(subctx->auxDataHash)); - fill_and_display_if_required("Auxiliary data hash", bufferHex, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char bufferHex[2 * 32 + 1] = {0}; + ui_getHexBufferScreen(bufferHex, SIZEOF(bufferHex), subctx->auxDataHash, SIZEOF(subctx->auxDataHash)); + fill_and_display_if_required("Auxiliary data hash", bufferHex, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { struct { diff --git a/src/signTxMint_ui.c b/src/signTxMint_ui.c index 9b703849..da7211f3 100644 --- a/src/signTxMint_ui.c +++ b/src/signTxMint_ui.c @@ -84,15 +84,15 @@ void signTxMint_handleTopLevelData_ui_runStep() snprintf(secondLine, SIZEOF(secondLine), "%u asset groups", subctx->numAssetGroups); ASSERT(strlen(secondLine) + 1 < SIZEOF(secondLine)); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "Mint", secondLine, this_fn ); -#elif defined(HAVE_NBGL) - display_prompt("Mint", secondLine, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_prompt("Mint", secondLine, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_MINT_TOP_LEVEL_DATA_RESPOND) { respondSuccessEmptyMsg(); @@ -127,42 +127,42 @@ void signTxMint_handleToken_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_TOKEN_STEP_DISPLAY_NAME) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayAssetFingerprintScreen( &subctx->stateData.tokenGroup, subctx->stateData.token.assetNameBytes, subctx->stateData.token.assetNameSize, this_fn ); -#elif defined(HAVE_NBGL) - char fingerprint[200] = {0}; + #elif defined(HAVE_NBGL) + char fingerprint[200] = {0}; ui_getAssetFingerprintScreen( - fingerprint, - SIZEOF(fingerprint), + fingerprint, + SIZEOF(fingerprint), &subctx->stateData.tokenGroup, subctx->stateData.token.assetNameBytes, subctx->stateData.token.assetNameSize ); - fill_and_display_if_required("Asset fingerprint", fingerprint, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required("Asset fingerprint", fingerprint, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_TOKEN_STEP_DISPLAY_AMOUNT) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayTokenAmountMintScreen( &subctx->stateData.tokenGroup, subctx->stateData.token.assetNameBytes, subctx->stateData.token.assetNameSize, subctx->stateData.token.amount, this_fn ); -#elif defined(HAVE_NBGL) - char tokenAmountStr[70] = {0}; + #elif defined(HAVE_NBGL) + char tokenAmountStr[70] = {0}; ui_getTokenAmountMintScreen( - tokenAmountStr, - SIZEOF(tokenAmountStr), + tokenAmountStr, + SIZEOF(tokenAmountStr), &subctx->stateData.tokenGroup, subctx->stateData.token.assetNameBytes, subctx->stateData.token.assetNameSize, subctx->stateData.token.amount ); - fill_and_display_if_required("Token amount", tokenAmountStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required("Token amount", tokenAmountStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_TOKEN_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -186,16 +186,16 @@ void signTxMint_handleConfirm_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPrompt( "Confirm", "mint?", this_fn, respond_with_user_reject ); -#elif defined(HAVE_NBGL) - display_confirmation("Confirm mint", "", "MINT\nCONFIRMED", "Mint\nrejected", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_confirmation("Confirm mint", "", "MINT\nCONFIRMED", "Mint\nrejected", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { respondSuccessEmptyMsg(); diff --git a/src/signTxOutput_ui.c b/src/signTxOutput_ui.c index f2e130c1..11e2287d 100644 --- a/src/signTxOutput_ui.c +++ b/src/signTxOutput_ui.c @@ -47,53 +47,53 @@ void signTx_handleOutput_address_bytes_ui_runStep() UI_STEP(HANDLE_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADDRESS) { ASSERT(subctx->stateData.destination.address.size <= SIZEOF(subctx->stateData.destination.address.buffer)); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayAddressScreen( "Send to address", subctx->stateData.destination.address.buffer, subctx->stateData.destination.address.size, this_fn ); -#elif defined(HAVE_NBGL) - char humanAddress[MAX_HUMAN_ADDRESS_SIZE] = {0}; + #elif defined(HAVE_NBGL) + char humanAddress[MAX_HUMAN_ADDRESS_SIZE] = {0}; ui_getAddressScreen( - humanAddress, - SIZEOF(humanAddress), + humanAddress, + SIZEOF(humanAddress), subctx->stateData.destination.address.buffer, subctx->stateData.destination.address.size ); - fill_and_display_if_required("Send to address", humanAddress, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required("Send to address", humanAddress, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_OUTPUT_ADDRESS_BYTES_STEP_WARNING_DATUM) { // this warning does not apply to address given by params where we only allow key hash spending part // in which case datum is just optional and rarely used if (_needsMissingDatumWarning()) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "WARNING: output", "could be unspendable due to missing datum", this_fn ); -#elif defined(HAVE_NBGL) - display_warning( - "Output could be unspendable\ndue to missing datum", - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_warning( + "Output could be unspendable\ndue to missing datum", + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } else { UI_STEP_JUMP(HANDLE_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADA_AMOUNT); } } UI_STEP(HANDLE_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADA_AMOUNT) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayAdaAmountScreen("Send", subctx->stateData.adaAmount, this_fn); -#elif defined(HAVE_NBGL) - char adaAmountStr[50] = {0}; - ui_getAdaAmountScreen(adaAmountStr, SIZEOF(adaAmountStr), subctx->stateData.adaAmount); - fill_and_display_if_required("Send", adaAmountStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char adaAmountStr[50] = {0}; + ui_getAdaAmountScreen(adaAmountStr, SIZEOF(adaAmountStr), subctx->stateData.adaAmount); + fill_and_display_if_required("Send", adaAmountStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_OUTPUT_ADDRESS_BYTES_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -113,33 +113,33 @@ void signTx_handleOutput_addressParams_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_BEGIN) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText(subctx->ui_text1, subctx->ui_text2, this_fn); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_prompt("Change output", "", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt("Change output", "", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_SPENDING_PATH) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displaySpendingInfoScreen(&subctx->stateData.destination.params, this_fn); -#elif defined(HAVE_NBGL) + #elif defined(HAVE_NBGL) #define SPENDING_INFO_SIZE MAX(11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX, 2 * BECH32_BUFFER_SIZE_MAX) - char line1[30]; - char spendingInfo[SPENDING_INFO_SIZE] = {0}; + char line1[30]; + char spendingInfo[SPENDING_INFO_SIZE] = {0}; ui_getSpendingInfoScreen(line1, SIZEOF(line1), spendingInfo, SIZEOF(spendingInfo), &subctx->stateData.destination.params); - fill_and_display_if_required(line1, spendingInfo, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required(line1, spendingInfo, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_STAKING_INFO) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayStakingInfoScreen(&subctx->stateData.destination.params, this_fn); -#elif defined(HAVE_NBGL) - char line1[30] = {0}; - char stakingInfo[120] = {0}; + #elif defined(HAVE_NBGL) + char line1[30] = {0}; + char stakingInfo[120] = {0}; ui_getStakingInfoScreen(line1, SIZEOF(line1), stakingInfo, SIZEOF(stakingInfo), &subctx->stateData.destination.params); - fill_and_display_if_required(line1, stakingInfo, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required(line1, stakingInfo, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS) { uint8_t addressBuffer[MAX_ADDRESS_SIZE] = {0}; @@ -147,34 +147,34 @@ void signTx_handleOutput_addressParams_ui_runStep() ASSERT(addressSize > 0); ASSERT(addressSize <= MAX_ADDRESS_SIZE); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayAddressScreen( subctx->ui_text3, addressBuffer, addressSize, this_fn ); -#elif defined(HAVE_NBGL) - char humanAddress[MAX_HUMAN_ADDRESS_SIZE] = {0}; + #elif defined(HAVE_NBGL) + char humanAddress[MAX_HUMAN_ADDRESS_SIZE] = {0}; ui_getAddressScreen( - humanAddress, - SIZEOF(humanAddress), + humanAddress, + SIZEOF(humanAddress), addressBuffer, addressSize ); - fill_and_display_if_required("Address", humanAddress, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required("Address", humanAddress, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_AMOUNT) { if (subctx->stateData.adaAmountSecurityPolicy == POLICY_ALLOW_WITHOUT_PROMPT) { UI_STEP_JUMP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_RESPOND); } else { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayAdaAmountScreen(subctx->ui_text4, subctx->stateData.adaAmount, this_fn); -#elif defined(HAVE_NBGL) - char adaAmountStr[50] = {0}; - ui_getAdaAmountScreen(adaAmountStr, SIZEOF(adaAmountStr), subctx->stateData.adaAmount); - fill_and_display_if_required(subctx->ui_text4, adaAmountStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char adaAmountStr[50] = {0}; + ui_getAdaAmountScreen(adaAmountStr, SIZEOF(adaAmountStr), subctx->stateData.adaAmount); + fill_and_display_if_required(subctx->ui_text4, adaAmountStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } } UI_STEP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_RESPOND) { @@ -195,48 +195,48 @@ void signTx_handleCollateralOutput_addressBytes_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_INTRO) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "Collateral", "return output", this_fn ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_prompt("Collateral\nreturn output", "", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt("Collateral\nreturn output", "", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADDRESS) { ASSERT(subctx->stateData.destination.address.size <= SIZEOF(subctx->stateData.destination.address.buffer)); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayAddressScreen( "Address", subctx->stateData.destination.address.buffer, subctx->stateData.destination.address.size, this_fn ); -#elif defined(HAVE_NBGL) - char humanAddress[MAX_HUMAN_ADDRESS_SIZE] = {0}; - ui_getAddressScreen( - humanAddress, - SIZEOF(humanAddress), - subctx->stateData.destination.address.buffer, - subctx->stateData.destination.address.size - ); - fill_and_display_if_required("Address", humanAddress, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char humanAddress[MAX_HUMAN_ADDRESS_SIZE] = {0}; + ui_getAddressScreen( + humanAddress, + SIZEOF(humanAddress), + subctx->stateData.destination.address.buffer, + subctx->stateData.destination.address.size + ); + fill_and_display_if_required("Address", humanAddress, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_DISPLAY_ADA_AMOUNT) { if (subctx->stateData.adaAmountSecurityPolicy == POLICY_ALLOW_WITHOUT_PROMPT) { UI_STEP_JUMP(HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_RESPOND); } else { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayAdaAmountScreen("Amount", subctx->stateData.adaAmount, this_fn); -#elif defined(HAVE_NBGL) - char adaAmountStr[50] = {0}; - ui_getAdaAmountScreen(adaAmountStr, SIZEOF(adaAmountStr), subctx->stateData.adaAmount); - fill_and_display_if_required("Amount", adaAmountStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char adaAmountStr[50] = {0}; + ui_getAdaAmountScreen(adaAmountStr, SIZEOF(adaAmountStr), subctx->stateData.adaAmount); + fill_and_display_if_required("Amount", adaAmountStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } } UI_STEP(HANDLE_COLLATERAL_OUTPUT_ADDRESS_BYTES_STEP_RESPOND) { @@ -257,42 +257,42 @@ void handleToken_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_TOKEN_STEP_DISPLAY_NAME) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayAssetFingerprintScreen( &subctx->stateData.tokenGroup, subctx->stateData.token.assetNameBytes, subctx->stateData.token.assetNameSize, this_fn ); -#elif defined(HAVE_NBGL) - char fingerprint[200] = {0}; + #elif defined(HAVE_NBGL) + char fingerprint[200] = {0}; ui_getAssetFingerprintScreen( - fingerprint, - SIZEOF(fingerprint), + fingerprint, + SIZEOF(fingerprint), &subctx->stateData.tokenGroup, subctx->stateData.token.assetNameBytes, subctx->stateData.token.assetNameSize ); - fill_and_display_if_required("Asset fingerprint", fingerprint, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required("Asset fingerprint", fingerprint, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_TOKEN_STEP_DISPLAY_AMOUNT) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayTokenAmountOutputScreen( &subctx->stateData.tokenGroup, subctx->stateData.token.assetNameBytes, subctx->stateData.token.assetNameSize, subctx->stateData.token.amount, this_fn ); -#elif defined(HAVE_NBGL) - char tokenAmountStr[70] = {0}; + #elif defined(HAVE_NBGL) + char tokenAmountStr[70] = {0}; ui_getTokenAmountOutputScreen( - tokenAmountStr, - SIZEOF(tokenAmountStr), + tokenAmountStr, + SIZEOF(tokenAmountStr), &subctx->stateData.tokenGroup, subctx->stateData.token.assetNameBytes, subctx->stateData.token.assetNameSize, subctx->stateData.token.amount ); - fill_and_display_if_required("Token amount", tokenAmountStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required("Token amount", tokenAmountStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_TOKEN_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -318,19 +318,19 @@ void signTxOutput_handleDatumHash_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_DATUM_HASH_STEP_DISPLAY) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayBech32Screen( "Datum hash", "datum", subctx->stateData.datumHash, OUTPUT_DATUM_HASH_LENGTH, this_fn ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; - ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "datum", subctx->stateData.datumHash, OUTPUT_DATUM_HASH_LENGTH); - fill_and_display_if_required("Datum hash", encodedStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "datum", subctx->stateData.datumHash, OUTPUT_DATUM_HASH_LENGTH); + fill_and_display_if_required("Datum hash", encodedStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_DATUM_HASH_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -361,16 +361,16 @@ void signTxOutput_handleDatumInline_ui_runStep() snprintf(l2 + len, SIZEOF(l2) - len, "..."); ASSERT(strlen(l2) + 1 < SIZEOF(l2)); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( l1, l2, this_fn ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_prompt(l1, l2, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt(l1, l2, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_DATUM_INLINE_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -402,16 +402,16 @@ void handleRefScript_ui_runStep() snprintf(l2 + len, SIZEOF(l2) - len, "..."); ASSERT(strlen(l2) + 1 < SIZEOF(l2)); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( l1, l2, this_fn ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_prompt(l1, l2, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt(l1, l2, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_SCRIPT_REF_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -431,17 +431,17 @@ void signTxOutput_handleConfirm_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPrompt( subctx->ui_text1, subctx->ui_text2, this_fn, respond_with_user_reject ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_confirmation("Confirm output", "", "OUTPUT\nCONFIRMED", "Output\nrejected", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_confirmation("Confirm output", "", "OUTPUT\nCONFIRMED", "Output\nrejected", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { respondSuccessEmptyMsg(); diff --git a/src/signTxOutput_ui.h b/src/signTxOutput_ui.h index 8c75f379..e61755a5 100644 --- a/src/signTxOutput_ui.h +++ b/src/signTxOutput_ui.h @@ -42,7 +42,7 @@ enum { }; void signTx_handleCollateralOutput_addressBytes_ui_runStep(); - + // ============================== TOKEN ============================== enum { diff --git a/src/signTxPoolRegistration_ui.c b/src/signTxPoolRegistration_ui.c index 4ef1ec26..d0087f67 100644 --- a/src/signTxPoolRegistration_ui.c +++ b/src/signTxPoolRegistration_ui.c @@ -105,20 +105,20 @@ void handlePoolInit_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_POOL_INIT_STEP_DISPLAY) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "Pool registration", "certificate", this_fn ); -#elif defined(HAVE_NBGL) + #elif defined(HAVE_NBGL) display_prompt( "Pool registration\ncertificate", - "", + "", this_fn, - respond_with_user_reject + respond_with_user_reject ); -#endif // HAVE_BAGL + #endif // HAVE_BAGL } UI_STEP(HANDLE_POOL_INIT_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -157,50 +157,50 @@ void handlePoolKey_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_POOL_KEY_STEP_DISPLAY_POOL_PATH) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPathScreen( "Pool ID path", &subctx->stateData.poolId.path, this_fn ); -#elif defined(HAVE_NBGL) - char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; - ui_getPathScreen( - pathStr, SIZEOF(pathStr), + #elif defined(HAVE_NBGL) + char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; + ui_getPathScreen( + pathStr, SIZEOF(pathStr), &subctx->stateData.poolId.path - ); - fill_and_display_if_required( - "Pool ID path", - pathStr, - this_fn, - respond_with_user_reject); -#endif // HAVE_BAGL + ); + fill_and_display_if_required( + "Pool ID path", + pathStr, + this_fn, + respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_POOL_KEY_STEP_DISPLAY_POOL_ID) { uint8_t poolKeyHash[POOL_KEY_HASH_LENGTH] = {0}; _toPoolKeyHash(&subctx->stateData.poolId, poolKeyHash); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayBech32Screen( "Pool ID", "pool", poolKeyHash, SIZEOF(poolKeyHash), this_fn ); -#elif defined(HAVE_NBGL) - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + #elif defined(HAVE_NBGL) + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; ui_getBech32Screen( - encodedStr, SIZEOF(encodedStr), + encodedStr, SIZEOF(encodedStr), "pool", poolKeyHash, SIZEOF(poolKeyHash) ); - fill_and_display_if_required( - "Pool ID", - encodedStr, - this_fn, - respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required( + "Pool ID", + encodedStr, + this_fn, + respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_POOL_KEY_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -221,26 +221,26 @@ void handlePoolVrfKey_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_POOL_VRF_KEY_STEP_DISPLAY) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayBech32Screen( "VRF key hash", "vrf_vk", subctx->stateData.vrfKeyHash, SIZEOF(subctx->stateData.vrfKeyHash), this_fn ); -#elif defined(HAVE_NBGL) - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + #elif defined(HAVE_NBGL) + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; ui_getBech32Screen( - encodedStr, SIZEOF(encodedStr), + encodedStr, SIZEOF(encodedStr), "vrf_vk", subctx->stateData.vrfKeyHash, SIZEOF(subctx->stateData.vrfKeyHash)); - fill_and_display_if_required( - "VRF key hash", - encodedStr, - this_fn, - respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required( + "VRF key hash", + encodedStr, + this_fn, + respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_POOL_VRF_KEY_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -261,70 +261,70 @@ void handlePoolFinancials_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_POOL_FINANCIALS_STEP_DISPLAY_PLEDGE) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayAdaAmountScreen( "Pledge", subctx->stateData.pledge, this_fn ); -#elif defined(HAVE_NBGL) - char adaAmountStr[50] = {0}; + #elif defined(HAVE_NBGL) + char adaAmountStr[50] = {0}; ui_getAdaAmountScreen( - adaAmountStr, SIZEOF(adaAmountStr), + adaAmountStr, SIZEOF(adaAmountStr), subctx->stateData.pledge ); - fill_and_display_if_required( - "Pledge", - adaAmountStr, - this_fn, - respond_with_user_reject + fill_and_display_if_required( + "Pledge", + adaAmountStr, + this_fn, + respond_with_user_reject ); -#endif // HAVE_BAGL + #endif // HAVE_BAGL } UI_STEP(HANDLE_POOL_FINANCIALS_STEP_DISPLAY_COST) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayAdaAmountScreen( "Cost", subctx->stateData.cost, this_fn ); -#elif defined(HAVE_NBGL) - char adaAmountStr[50] = {0}; + #elif defined(HAVE_NBGL) + char adaAmountStr[50] = {0}; ui_getAdaAmountScreen( - adaAmountStr, SIZEOF(adaAmountStr), - subctx->stateData.cost + adaAmountStr, SIZEOF(adaAmountStr), + subctx->stateData.cost ); - - fill_and_display_if_required( - "Cost", - adaAmountStr, - this_fn, - respond_with_user_reject + + fill_and_display_if_required( + "Cost", + adaAmountStr, + this_fn, + respond_with_user_reject ); -#endif // HAVE_BAGL + #endif // HAVE_BAGL } UI_STEP(HANDLE_POOL_FINANCIALS_STEP_DISPLAY_MARGIN) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPoolMarginScreen( subctx->stateData.marginNumerator, subctx->stateData.marginDenominator, this_fn ); -#elif defined(HAVE_NBGL) - char marginStr[20] = {0}; + #elif defined(HAVE_NBGL) + char marginStr[20] = {0}; ui_getPoolMarginScreen( - marginStr, SIZEOF(marginStr), + marginStr, SIZEOF(marginStr), subctx->stateData.marginNumerator, subctx->stateData.marginDenominator ); - fill_and_display_if_required( - "Profit margin", - marginStr, - this_fn, - respond_with_user_reject + fill_and_display_if_required( + "Profit margin", + marginStr, + this_fn, + respond_with_user_reject ); -#endif // HAVE_BAGL + #endif // HAVE_BAGL } UI_STEP(HANDLE_POOL_FINANCIALS_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -349,28 +349,28 @@ void handlePoolRewardAccount_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_POOL_REWARD_ACCOUNT_STEP_DISPLAY) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayRewardAccountScreen( &subctx->stateData.poolRewardAccount, commonTxData->networkId, this_fn ); -#elif defined(HAVE_NBGL) - char firstLine[32] = {0}; - char secondLine[BIP44_PATH_STRING_SIZE_MAX + MAX_HUMAN_REWARD_ACCOUNT_SIZE + 2] = {0}; - ui_getRewardAccountScreen( - firstLine, SIZEOF(firstLine), - secondLine, SIZEOF(secondLine), + #elif defined(HAVE_NBGL) + char firstLine[32] = {0}; + char secondLine[BIP44_PATH_STRING_SIZE_MAX + MAX_HUMAN_REWARD_ACCOUNT_SIZE + 2] = {0}; + ui_getRewardAccountScreen( + firstLine, SIZEOF(firstLine), + secondLine, SIZEOF(secondLine), &subctx->stateData.poolRewardAccount, commonTxData->networkId - ); - fill_and_display_if_required( - firstLine, - secondLine, - handlePoolRewardAccount_ui_runStep_cb, - respond_with_user_reject - ); -#endif // HAVE_BAGL + ); + fill_and_display_if_required( + firstLine, + secondLine, + handlePoolRewardAccount_ui_runStep_cb, + respond_with_user_reject + ); + #endif // HAVE_BAGL } UI_STEP(HANDLE_POOL_REWARD_ACCOUNT_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -391,24 +391,24 @@ void handleOwner_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_OWNER_STEP_DISPLAY) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPoolOwnerScreen(&subctx->stateData.owner, subctx->currentOwner, commonTxData->networkId, this_fn); -#elif defined(HAVE_NBGL) - char firstLine[32] = {0}; - char secondLine[BIP44_PATH_STRING_SIZE_MAX + MAX_HUMAN_REWARD_ACCOUNT_SIZE + 2] = {0}; + #elif defined(HAVE_NBGL) + char firstLine[32] = {0}; + char secondLine[BIP44_PATH_STRING_SIZE_MAX + MAX_HUMAN_REWARD_ACCOUNT_SIZE + 2] = {0}; ui_getPoolOwnerScreen( - firstLine, SIZEOF(firstLine), - secondLine, SIZEOF(secondLine), - &subctx->stateData.owner, subctx->currentOwner, - commonTxData->networkId - ); - fill_and_display_if_required( - firstLine, - secondLine, - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + firstLine, SIZEOF(firstLine), + secondLine, SIZEOF(secondLine), + &subctx->stateData.owner, subctx->currentOwner, + commonTxData->networkId + ); + fill_and_display_if_required( + firstLine, + secondLine, + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } UI_STEP(HANDLE_OWNER_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -435,80 +435,80 @@ void handleRelay_ip_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_RELAY_IP_STEP_DISPLAY_NUMBER) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPoolRelayScreen( relay, subctx->currentRelay, this_fn ); -#elif defined(HAVE_NBGL) - char line[20] = {0}; + #elif defined(HAVE_NBGL) + char line[20] = {0}; ui_getPoolRelayScreen( line, SIZEOF(line), subctx->currentRelay ); - fill_and_display_if_required("Relay index", line, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required("Relay index", line, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_RELAY_IP_STEP_DISPLAY_IPV4) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayIpv4Screen( &relay->ipv4, this_fn ); -#elif defined(HAVE_NBGL) - char ipStr[IPV4_STR_SIZE_MAX + 1] = {0}; + #elif defined(HAVE_NBGL) + char ipStr[IPV4_STR_SIZE_MAX + 1] = {0}; ui_getIpv4Screen( - ipStr, SIZEOF(ipStr), + ipStr, SIZEOF(ipStr), &relay->ipv4 ); - fill_and_display_if_required( - "IPv4 address", - ipStr, - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + fill_and_display_if_required( + "IPv4 address", + ipStr, + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } UI_STEP(HANDLE_RELAY_IP_STEP_DISPLAY_IPV6) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayIpv6Screen( &relay->ipv6, this_fn ); -#elif defined(HAVE_NBGL) - char ipStr[IPV6_STR_SIZE_MAX + 1] = {0}; + #elif defined(HAVE_NBGL) + char ipStr[IPV6_STR_SIZE_MAX + 1] = {0}; ui_getIpv6Screen( - ipStr, SIZEOF(ipStr), + ipStr, SIZEOF(ipStr), &relay->ipv6 ); - fill_and_display_if_required( - "IPv6 address", - ipStr, - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + fill_and_display_if_required( + "IPv6 address", + ipStr, + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } UI_STEP(HANDLE_RELAY_IP_STEP_DISPLAY_PORT) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayIpPortScreen( &relay->port, this_fn ); -#elif defined(HAVE_NBGL) - char portStr[1 + (sizeof "65536")] = {0}; + #elif defined(HAVE_NBGL) + char portStr[1 + (sizeof "65536")] = {0}; ui_getIpPortScreen( - portStr, SIZEOF(portStr), + portStr, SIZEOF(portStr), &relay->port ); - fill_and_display_if_required( - "Port", - portStr, - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + fill_and_display_if_required( + "Port", + portStr, + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } UI_STEP(HANDLE_RELAY_IP_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -535,20 +535,20 @@ void handleRelay_dns_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_RELAY_DNS_STEP_DISPLAY_NUMBER) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPoolRelayScreen( relay, subctx->currentRelay, this_fn ); -#elif defined(HAVE_NBGL) - char line[20] = {0}; + #elif defined(HAVE_NBGL) + char line[20] = {0}; ui_getPoolRelayScreen( line, SIZEOF(line), subctx->currentRelay ); - fill_and_display_if_required("Relay index", line, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required("Relay index", line, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_RELAY_DNS_STEP_DISPLAY_DNSNAME) { char dnsNameStr[1 + DNS_NAME_SIZE_MAX] = {0}; @@ -558,20 +558,20 @@ void handleRelay_dns_ui_runStep() dnsNameStr[relay->dnsNameSize] = '\0'; ASSERT(strlen(dnsNameStr) == relay->dnsNameSize); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "DNS name", dnsNameStr, this_fn ); -#elif defined(HAVE_NBGL) - fill_and_display_if_required( + #elif defined(HAVE_NBGL) + fill_and_display_if_required( "DNS name", dnsNameStr, this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + respond_with_user_reject + ); + #endif // HAVE_BAGL } UI_STEP(HANDLE_RELAY_DNS_STEP_DISPLAY_PORT) { if (relay->format == RELAY_MULTIPLE_HOST_NAME) { @@ -579,24 +579,24 @@ void handleRelay_dns_ui_runStep() UI_STEP_JUMP(HANDLE_RELAY_DNS_STEP_RESPOND); } -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayIpPortScreen( &relay->port, this_fn ); -#elif defined(HAVE_NBGL) - char portStr[1 + (sizeof "65536")] = {0}; + #elif defined(HAVE_NBGL) + char portStr[1 + (sizeof "65536")] = {0}; ui_getIpPortScreen( - portStr, SIZEOF(portStr), + portStr, SIZEOF(portStr), &relay->port ); - fill_and_display_if_required( - "Port", - portStr, - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + fill_and_display_if_required( + "Port", + portStr, + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } UI_STEP(HANDLE_RELAY_DNS_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -624,20 +624,20 @@ void handleNullMetadata_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_NULL_METADATA_STEP_DISPLAY) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "No metadata", "(anonymous pool)", this_fn ); -#elif defined(HAVE_NBGL) - fill_and_display_if_required( - "Metadata", - "None: anymous pool", - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + fill_and_display_if_required( + "Metadata", + "None: anymous pool", + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } UI_STEP(HANDLE_NULL_METADATA_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -665,20 +665,20 @@ void handleMetadata_ui_runStep() metadataUrlStr[md->urlSize] = '\0'; ASSERT(strlen(metadataUrlStr) == md->urlSize); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "Pool metadata url", metadataUrlStr, this_fn ); -#elif defined(HAVE_NBGL) - fill_and_display_if_required( - "Pool metadata url", + #elif defined(HAVE_NBGL) + fill_and_display_if_required( + "Pool metadata url", metadataUrlStr, - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } UI_STEP(HANDLE_METADATA_STEP_DISPLAY_HASH) { char metadataHashHex[1 + 2 * POOL_METADATA_HASH_LENGTH] = {0}; @@ -689,20 +689,20 @@ void handleMetadata_ui_runStep() ); ASSERT(len + 1 == SIZEOF(metadataHashHex)); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "Pool metadata hash", metadataHashHex, this_fn ); -#elif defined(HAVE_NBGL) - fill_and_display_if_required( + #elif defined(HAVE_NBGL) + fill_and_display_if_required( "Pool metadata hash", metadataHashHex, - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } UI_STEP(HANDLE_METADATA_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -727,20 +727,20 @@ void signTxPoolRegistration_handleConfirm_ui_runStep() // missing owners or relays UI_STEP(HANDLE_CONFIRM_STEP_FINAL_NO_OWNERS) { if (subctx->numOwners == 0) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "No", "pool owners", this_fn ); -#elif defined(HAVE_NBGL) - fill_and_display_if_required( - "Pool owners", - "None", - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + fill_and_display_if_required( + "Pool owners", + "None", + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } else { UI_STEP_JUMP(HANDLE_CONFIRM_STEP_FINAL_NO_RELAYS); } @@ -748,42 +748,42 @@ void signTxPoolRegistration_handleConfirm_ui_runStep() UI_STEP(HANDLE_CONFIRM_STEP_FINAL_NO_RELAYS) { bool isOperator = commonTxData->txSigningMode == SIGN_TX_SIGNINGMODE_POOL_REGISTRATION_OPERATOR; if ((subctx->numRelays == 0) && isOperator) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "No", "pool relays", this_fn ); -#elif defined(HAVE_NBGL) - fill_and_display_if_required( - "Pool relays", - "None", - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + fill_and_display_if_required( + "Pool relays", + "None", + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } else { UI_STEP_JUMP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM); } } UI_STEP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPrompt( "Confirm stake", "pool registration?", this_fn, respond_with_user_reject ); -#elif defined(HAVE_NBGL) - display_confirmation( - "Confirm stake pool\nregistration", - "", - "STAKE POOL\nREGISTERED", - "Stake pool\nrejected", - this_fn, - respond_with_user_reject - ); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_confirmation( + "Confirm stake pool\nregistration", + "", + "STAKE POOL\nREGISTERED", + "Stake pool\nrejected", + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL } UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { respondSuccessEmptyMsg(); diff --git a/src/signTxUtils.c b/src/signTxUtils.c index f06926e0..811c506d 100644 --- a/src/signTxUtils.c +++ b/src/signTxUtils.c @@ -17,9 +17,9 @@ void respondSuccessEmptyMsg() { TRACE(); io_send_buf(SUCCESS, NULL, 0); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayBusy(); // displays dots, called only after I/O to avoid freezing -#endif + #endif } bool violatesSingleAccountOrStoreIt(const bip44_path_t* path) diff --git a/src/signTx_ui.c b/src/signTx_ui.c index ea5a6a7d..00ef6930 100644 --- a/src/signTx_ui.c +++ b/src/signTx_ui.c @@ -32,39 +32,39 @@ static const char* _newTxLine1(sign_tx_signingmode_t txSigningMode) switch (txSigningMode) { case SIGN_TX_SIGNINGMODE_ORDINARY_TX: -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL return "New ordinary"; -#elif defined(HAVE_NBGL) + #elif defined(HAVE_NBGL) return "New ordinary\ntransaction"; -#endif // HAVE_BAGL + #endif // HAVE_BAGL case SIGN_TX_SIGNINGMODE_POOL_REGISTRATION_OWNER: -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL return "New pool owner"; -#elif defined(HAVE_NBGL) + #elif defined(HAVE_NBGL) return "New pool owner\ntransaction"; -#endif // HAVE_BAGL + #endif // HAVE_BAGL case SIGN_TX_SIGNINGMODE_POOL_REGISTRATION_OPERATOR: -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL return "New pool operator"; -#elif defined(HAVE_NBGL) + #elif defined(HAVE_NBGL) return "New pool operator\ntransaction"; -#endif // HAVE_BAGL + #endif // HAVE_BAGL case SIGN_TX_SIGNINGMODE_MULTISIG_TX: -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL return "New multisig"; -#elif defined(HAVE_NBGL) + #elif defined(HAVE_NBGL) return "New multisig\ntransaction"; -#endif // HAVE_BAGL + #endif // HAVE_BAGL case SIGN_TX_SIGNINGMODE_PLUTUS_TX: -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL return "New Plutus"; -#elif defined(HAVE_NBGL) + #elif defined(HAVE_NBGL) return "New Plutus\ntransaction"; -#endif // HAVE_BAGL + #endif // HAVE_BAGL default: ASSERT(false); @@ -72,13 +72,14 @@ static const char* _newTxLine1(sign_tx_signingmode_t txSigningMode) } #ifdef HAVE_NBGL -static void signTx_handleInit_ui_runStep_cb(void) { - char networkParams[100] = {0}; - ui_getNetworkParamsScreen_2( - networkParams, - SIZEOF(networkParams), - ctx->commonTxData.protocolMagic); - fill_and_display_if_required("Protocol magic", networkParams, signTx_handleInit_ui_runStep, respond_with_user_reject); +static void signTx_handleInit_ui_runStep_cb(void) +{ + char networkParams[100] = {0}; + ui_getNetworkParamsScreen_2( + networkParams, + SIZEOF(networkParams), + ctx->commonTxData.protocolMagic); + fill_and_display_if_required("Protocol magic", networkParams, signTx_handleInit_ui_runStep, respond_with_user_reject); } #endif // HAVE_NBGL @@ -91,16 +92,16 @@ void signTx_handleInit_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(HANDLE_INIT_STEP_PROMPT_SIGNINGMODE) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPrompt( _newTxLine1(ctx->commonTxData.txSigningMode), "transaction?", this_fn, respond_with_user_reject ); -#elif defined(HAVE_NBGL) - display_prompt(_newTxLine1(ctx->commonTxData.txSigningMode), "", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_prompt(_newTxLine1(ctx->commonTxData.txSigningMode), "", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_INIT_STEP_DISPLAY_NETWORK_DETAILS) { @@ -114,31 +115,31 @@ void signTx_handleInit_ui_runStep() // no need to display the network details UI_STEP_JUMP(HANDLE_INIT_STEP_SCRIPT_RUNNING_WARNING); } -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayNetworkParamsScreen( "Network details", ctx->commonTxData.networkId, ctx->commonTxData.protocolMagic, this_fn ); -#elif defined(HAVE_NBGL) - char networkParams[100] = {0}; + #elif defined(HAVE_NBGL) + char networkParams[100] = {0}; ui_getNetworkParamsScreen_1( - networkParams, - SIZEOF(networkParams), - ctx->commonTxData.networkId); - fill_and_display_if_required("Network ID", networkParams, signTx_handleInit_ui_runStep_cb, respond_with_user_reject); -#endif // HAVE_BAGL + networkParams, + SIZEOF(networkParams), + ctx->commonTxData.networkId); + fill_and_display_if_required("Network ID", networkParams, signTx_handleInit_ui_runStep_cb, respond_with_user_reject); + #endif // HAVE_BAGL } else { // technically, no pool reg. certificate as well, but the UI message would be too long -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "Warning:", "cannot verify network id: no outputs or withdrawals", this_fn ); -#elif defined(HAVE_NBGL) - display_warning("Cannot verify network id:\nno outputs, or withdrawals", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_warning("Cannot verify network id:\nno outputs, or withdrawals", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } } @@ -146,44 +147,44 @@ void signTx_handleInit_ui_runStep() if (!needsRunningScriptWarning(ctx->numCollateralInputs)) { UI_STEP_JUMP(HANDLE_INIT_STEP_NO_COLLATERAL_WARNING); } -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText("WARNING:", "Plutus script will be evaluated", this_fn); -#elif defined(HAVE_NBGL) - display_warning("Plutus script will be evaluated", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_warning("Plutus script will be evaluated", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_INIT_STEP_NO_COLLATERAL_WARNING) { if (!needsMissingCollateralWarning(ctx->commonTxData.txSigningMode, ctx->numCollateralInputs)) { UI_STEP_JUMP(HANDLE_INIT_STEP_NO_SCRIPT_DATA_HASH_WARNING); } -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText("WARNING:", "No collateral given for Plutus transaction", this_fn); -#elif defined(HAVE_NBGL) - display_warning("No collateral given for\nPlutus transaction", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_warning("No collateral given for\nPlutus transaction", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_INIT_STEP_UNKNOWN_COLLATERAL_WARNING) { if (!needsUnknownCollateralWarning(ctx->commonTxData.txSigningMode, ctx->includeTotalCollateral)) { UI_STEP_JUMP(HANDLE_INIT_STEP_NO_SCRIPT_DATA_HASH_WARNING); } -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText("WARNING:", "Unknown collateral amount", this_fn); -#elif defined(HAVE_NBGL) - display_warning("Unknown collateral amount", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_warning("Unknown collateral amount", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_INIT_STEP_NO_SCRIPT_DATA_HASH_WARNING) { if (!needsMissingScriptDataHashWarning(ctx->commonTxData.txSigningMode, ctx->includeScriptDataHash)) { UI_STEP_JUMP(HANDLE_INIT_STEP_RESPOND); } -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText("WARNING:", "No script data given for Plutus transaction", this_fn); -#elif defined(HAVE_NBGL) - display_warning("No script data given for\nPlutus transaction", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_warning("No script data given for\nPlutus transaction", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_INIT_STEP_RESPOND) { @@ -204,18 +205,18 @@ void signTx_handleAuxDataArbitraryHash_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(HANDLE_AUX_DATA_ARBITRARY_HASH_STEP_DISPLAY) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayHexBufferScreen( "Auxiliary data hash", ctx->auxDataHash, SIZEOF(ctx->auxDataHash), this_fn ); -#elif defined(HAVE_NBGL) - char bufferHex[2 * 32 + 1] = {0}; - ui_getHexBufferScreen(bufferHex, SIZEOF(bufferHex), ctx->auxDataHash, SIZEOF(ctx->auxDataHash)); - fill_and_display_if_required("Auxiliary data hash", bufferHex, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char bufferHex[2 * 32 + 1] = {0}; + ui_getHexBufferScreen(bufferHex, SIZEOF(bufferHex), ctx->auxDataHash, SIZEOF(ctx->auxDataHash)); + fill_and_display_if_required("Auxiliary data hash", bufferHex, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_AUX_DATA_ARBITRARY_HASH_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -233,17 +234,17 @@ void signTx_handleAuxDataCVoteRegistration_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(HANDLE_AUX_DATA_CVOTE_REGISTRATION_STEP_DISPLAY) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPrompt( "Register vote", "key (CIP-36)?", this_fn, respond_with_user_reject ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_prompt("Register vote\nkey (CIP-36)?", "", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt("Register vote\nkey (CIP-36)?", "", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_AUX_DATA_CVOTE_REGISTRATION_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -263,16 +264,16 @@ void signTx_handleInput_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(HANDLE_INPUT_STEP_DISPLAY) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayInputScreen(&BODY_CTX->stageData.input, this_fn); -#elif defined(HAVE_NBGL) - // index 32 bit (10) + separator (" / ") + utxo hash hex format + \0 - // + 1 byte to detect if everything has been written - char inputStr[10 + 3 + TX_HASH_LENGTH * 2 + 1 + 1] = {0}; + #elif defined(HAVE_NBGL) + // index 32 bit (10) + separator (" / ") + utxo hash hex format + \0 + // + 1 byte to detect if everything has been written + char inputStr[10 + 3 + TX_HASH_LENGTH * 2 + 1 + 1] = {0}; - ui_getInputScreen(inputStr, SIZEOF(inputStr), &BODY_CTX->stageData.input); - fill_and_display_if_required(BODY_CTX->stageData.input.label, inputStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + ui_getInputScreen(inputStr, SIZEOF(inputStr), &BODY_CTX->stageData.input); + fill_and_display_if_required(BODY_CTX->stageData.input.label, inputStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_INPUT_STEP_RESPOND) { @@ -296,13 +297,13 @@ void signTx_handleFee_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(HANDLE_FEE_STEP_DISPLAY) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayAdaAmountScreen("Transaction fee", BODY_CTX->stageData.fee, this_fn); -#elif defined(HAVE_NBGL) - char adaAmountStr[50] = {0}; - ui_getAdaAmountScreen(adaAmountStr, SIZEOF(adaAmountStr), BODY_CTX->stageData.fee); - fill_and_display_if_required("Transaction fee", adaAmountStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char adaAmountStr[50] = {0}; + ui_getAdaAmountScreen(adaAmountStr, SIZEOF(adaAmountStr), BODY_CTX->stageData.fee); + fill_and_display_if_required("Transaction fee", adaAmountStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_FEE_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -321,18 +322,18 @@ void signTx_handleTtl_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(HANDLE_TTL_STEP_DISPLAY) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayValidityBoundaryScreen( "Transaction TTL", BODY_CTX->stageData.ttl, ctx->commonTxData.networkId, ctx->commonTxData.protocolMagic, this_fn ); -#elif defined(HAVE_NBGL) - char boundaryStr[30] = {0}; - ui_getValidityBoundaryScreen(boundaryStr, SIZEOF(boundaryStr), BODY_CTX->stageData.ttl, ctx->commonTxData.networkId, ctx->commonTxData.protocolMagic); - fill_and_display_if_required("Transaction TTL", boundaryStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char boundaryStr[30] = {0}; + ui_getValidityBoundaryScreen(boundaryStr, SIZEOF(boundaryStr), BODY_CTX->stageData.ttl, ctx->commonTxData.networkId, ctx->commonTxData.protocolMagic); + fill_and_display_if_required("Transaction TTL", boundaryStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_TTL_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -370,10 +371,11 @@ static inline void advanceCertificatesStateIfAppropriate() } #ifdef HAVE_NBGL -static void signTx_handleCertificate_ui_delegation_cb(void) { - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; - ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "pool", BODY_CTX->stageData.certificate.poolKeyHash, SIZEOF(BODY_CTX->stageData.certificate.poolKeyHash)); - fill_and_display_if_required("Pool", encodedStr, signTx_handleCertificate_ui_runStep, respond_with_user_reject); +static void signTx_handleCertificate_ui_delegation_cb(void) +{ + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "pool", BODY_CTX->stageData.certificate.poolKeyHash, SIZEOF(BODY_CTX->stageData.certificate.poolKeyHash)); + fill_and_display_if_required("Pool", encodedStr, signTx_handleCertificate_ui_runStep, respond_with_user_reject); } #endif @@ -387,43 +389,43 @@ void signTx_handleCertificate_ui_runStep() UI_STEP(HANDLE_CERTIFICATE_STEP_DISPLAY_OPERATION) { switch (BODY_CTX->stageData.certificate.type) { case CERTIFICATE_TYPE_STAKE_REGISTRATION: -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "Register", "staking key", this_fn ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_prompt("Register\nstaking key", "", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt("Register\nstaking key", "", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL break; case CERTIFICATE_TYPE_STAKE_DEREGISTRATION: -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "Deregister", "staking key", this_fn ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_prompt("Deregister\nstaking key", "", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt("Deregister\nstaking key", "", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL break; case CERTIFICATE_TYPE_STAKE_DELEGATION: -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayBech32Screen( "Delegate stake to", "pool", BODY_CTX->stageData.certificate.poolKeyHash, SIZEOF(BODY_CTX->stageData.certificate.poolKeyHash), this_fn ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_prompt("Delegate staking\nconfirmation key", "", signTx_handleCertificate_ui_delegation_cb, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt("Delegate staking\nconfirmation key", "", signTx_handleCertificate_ui_delegation_cb, respond_with_user_reject); + #endif // HAVE_BAGL break; default: @@ -436,22 +438,22 @@ void signTx_handleCertificate_ui_runStep() UI_STEP(HANDLE_CERTIFICATE_STEP_DISPLAY_STAKING_KEY) { switch (BODY_CTX->stageData.certificate.stakeCredential.type) { case STAKE_CREDENTIAL_KEY_PATH: -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPathScreen( "Staking key", &BODY_CTX->stageData.certificate.stakeCredential.keyPath, this_fn ); -#elif defined(HAVE_NBGL) - { - char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; - ui_getPathScreen(pathStr, SIZEOF(pathStr), &BODY_CTX->stageData.certificate.stakeCredential.keyPath); - fill_and_display_if_required("Staking key", pathStr, this_fn, respond_with_user_reject); - } -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + { + char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; + ui_getPathScreen(pathStr, SIZEOF(pathStr), &BODY_CTX->stageData.certificate.stakeCredential.keyPath); + fill_and_display_if_required("Staking key", pathStr, this_fn, respond_with_user_reject); + } + #endif // HAVE_BAGL break; case STAKE_CREDENTIAL_KEY_HASH: -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayBech32Screen( "Staking key hash", "stake_vkh", @@ -459,16 +461,16 @@ void signTx_handleCertificate_ui_runStep() SIZEOF(BODY_CTX->stageData.certificate.stakeCredential.keyHash), this_fn ); -#elif defined(HAVE_NBGL) - { - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; - ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "stake_vkh", BODY_CTX->stageData.certificate.stakeCredential.keyHash, SIZEOF(BODY_CTX->stageData.certificate.stakeCredential.keyHash)); - fill_and_display_if_required("Staking key hash", encodedStr, this_fn, respond_with_user_reject); - } -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + { + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "stake_vkh", BODY_CTX->stageData.certificate.stakeCredential.keyHash, SIZEOF(BODY_CTX->stageData.certificate.stakeCredential.keyHash)); + fill_and_display_if_required("Staking key hash", encodedStr, this_fn, respond_with_user_reject); + } + #endif // HAVE_BAGL break; case STAKE_CREDENTIAL_SCRIPT_HASH: -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayBech32Screen( "Staking script hash", "script", @@ -476,13 +478,13 @@ void signTx_handleCertificate_ui_runStep() SIZEOF(BODY_CTX->stageData.certificate.stakeCredential.scriptHash), this_fn ); -#elif defined(HAVE_NBGL) - { - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; - ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "script", BODY_CTX->stageData.certificate.stakeCredential.scriptHash, SIZEOF(BODY_CTX->stageData.certificate.stakeCredential.scriptHash)); - fill_and_display_if_required("Staking script hash", encodedStr, this_fn, respond_with_user_reject); - } -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + { + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "script", BODY_CTX->stageData.certificate.stakeCredential.scriptHash, SIZEOF(BODY_CTX->stageData.certificate.stakeCredential.scriptHash)); + fill_and_display_if_required("Staking script hash", encodedStr, this_fn, respond_with_user_reject); + } + #endif // HAVE_BAGL break; default: ASSERT(false); @@ -495,27 +497,27 @@ void signTx_handleCertificate_ui_runStep() switch (BODY_CTX->stageData.certificate.type) { case CERTIFICATE_TYPE_STAKE_REGISTRATION: -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL snprintf(description, SIZEOF(description), "registration?"); -#elif defined(HAVE_NBGL) - display_confirmation("Confirm\nregistration", "", "REGISTRATION\nACCEPTED", "Registration\nrejected", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_confirmation("Confirm\nregistration", "", "REGISTRATION\nACCEPTED", "Registration\nrejected", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL break; case CERTIFICATE_TYPE_STAKE_DEREGISTRATION: -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL snprintf(description, SIZEOF(description), "deregistration?"); -#elif defined(HAVE_NBGL) - display_confirmation("Confirm\nderegistration", "", "DEREGISTRATION\nACCEPTED", "Deregistration\nrejected", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_confirmation("Confirm\nderegistration", "", "DEREGISTRATION\nACCEPTED", "Deregistration\nrejected", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL break; case CERTIFICATE_TYPE_STAKE_DELEGATION: -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL snprintf(description, SIZEOF(description), "delegation?"); -#elif defined(HAVE_NBGL) - display_confirmation("Confirm\ndelegation", "", "DELEGATION\nACCEPTED", "Delegation\nrejected", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_confirmation("Confirm\ndelegation", "", "DELEGATION\nACCEPTED", "Delegation\nrejected", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL break; default: @@ -524,15 +526,15 @@ void signTx_handleCertificate_ui_runStep() // make sure all the information is displayed to the user ASSERT(strlen(description) + 1 < SIZEOF(description)); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPrompt( "Confirm", description, this_fn, respond_with_user_reject ); -#elif defined(HAVE_NBGL) -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + #endif // HAVE_BAGL } UI_STEP(HANDLE_CERTIFICATE_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -552,48 +554,48 @@ void signTx_handleCertificatePoolRetirement_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_DISPLAY_OPERATION) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayBech32Screen( "Retire stake pool", "pool", BODY_CTX->stageData.certificate.poolKeyHash, SIZEOF(BODY_CTX->stageData.certificate.poolKeyHash), this_fn ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; - ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "pool", BODY_CTX->stageData.certificate.poolKeyHash, SIZEOF(BODY_CTX->stageData.certificate.poolKeyHash)); - fill_and_display_if_required("Retire stake pool", encodedStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "pool", BODY_CTX->stageData.certificate.poolKeyHash, SIZEOF(BODY_CTX->stageData.certificate.poolKeyHash)); + fill_and_display_if_required("Retire stake pool", encodedStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_DISPLAY_EPOCH) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayUint64Screen( "at the start of epoch", BODY_CTX->stageData.certificate.epoch, this_fn ); -#elif defined(HAVE_NBGL) - char line[30]; + #elif defined(HAVE_NBGL) + char line[30]; ui_getUint64Screen( - line, - SIZEOF(line), + line, + SIZEOF(line), BODY_CTX->stageData.certificate.epoch ); - fill_and_display_if_required("Start of epoch", line, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required("Start of epoch", line, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_CONFIRM) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPrompt( "Confirm", "pool retirement", this_fn, respond_with_user_reject ); -#elif defined(HAVE_NBGL) - display_confirmation("Confirm\npool retirement", "", "POOL RETIREMENT\nCONFIRMED", "Pool retirement\nrejected", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_confirmation("Confirm\npool retirement", "", "POOL RETIREMENT\nCONFIRMED", "Pool retirement\nrejected", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -614,13 +616,13 @@ void signTx_handleWithdrawal_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(HANDLE_WITHDRAWAL_STEP_DISPLAY_AMOUNT) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayAdaAmountScreen("Withdrawing rewards", BODY_CTX->stageData.withdrawal.amount, this_fn); -#elif defined(HAVE_NBGL) - char adaAmountStr[50] = {0}; - ui_getAdaAmountScreen(adaAmountStr, SIZEOF(adaAmountStr), BODY_CTX->stageData.withdrawal.amount); - fill_and_display_if_required("Withdrawing rewards", adaAmountStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char adaAmountStr[50] = {0}; + ui_getAdaAmountScreen(adaAmountStr, SIZEOF(adaAmountStr), BODY_CTX->stageData.withdrawal.amount); + fill_and_display_if_required("Withdrawing rewards", adaAmountStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_WITHDRAWAL_STEP_DISPLAY_PATH) { reward_account_t rewardAccount; @@ -658,15 +660,15 @@ void signTx_handleWithdrawal_ui_runStep() ASSERT(false); break; } -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayRewardAccountScreen(&rewardAccount, ctx->commonTxData.networkId, this_fn); -#elif defined(HAVE_NBGL) - char firstLine[32] = {0}; - char secondLine[BIP44_PATH_STRING_SIZE_MAX + MAX_HUMAN_REWARD_ACCOUNT_SIZE + 2] = {0}; - ui_getRewardAccountScreen(firstLine, SIZEOF(firstLine), secondLine, SIZEOF(secondLine), &rewardAccount, ctx->commonTxData.networkId); - fill_and_display_if_required(firstLine, secondLine, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL - } + #elif defined(HAVE_NBGL) + char firstLine[32] = {0}; + char secondLine[BIP44_PATH_STRING_SIZE_MAX + MAX_HUMAN_REWARD_ACCOUNT_SIZE + 2] = {0}; + ui_getRewardAccountScreen(firstLine, SIZEOF(firstLine), secondLine, SIZEOF(secondLine), &rewardAccount, ctx->commonTxData.networkId); + fill_and_display_if_required(firstLine, secondLine, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL + } UI_STEP(HANDLE_WITHDRAWAL_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -691,18 +693,18 @@ void signTx_handleValidityInterval_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(HANDLE_VALIDITY_INTERVAL_START_STEP_DISPLAY) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayValidityBoundaryScreen( "Validity interval start", BODY_CTX->stageData.validityIntervalStart, ctx->commonTxData.networkId, ctx->commonTxData.protocolMagic, this_fn ); -#elif defined(HAVE_NBGL) - char boundaryStr[30] = {0}; + #elif defined(HAVE_NBGL) + char boundaryStr[30] = {0}; ui_getValidityBoundaryScreen(boundaryStr, SIZEOF(boundaryStr), BODY_CTX->stageData.validityIntervalStart, ctx->commonTxData.networkId, ctx->commonTxData.protocolMagic); - fill_and_display_if_required("Validity interval start", boundaryStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + fill_and_display_if_required("Validity interval start", boundaryStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_VALIDITY_INTERVAL_START_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -721,18 +723,18 @@ void signTx_handleScriptDataHash_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(HANDLE_SCRIPT_DATA_HASH_STEP_DISPLAY) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayBech32Screen( "Script data hash", "script_data", BODY_CTX->stageData.scriptDataHash, SCRIPT_DATA_HASH_LENGTH, this_fn ); -#elif defined(HAVE_NBGL) - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; - ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "script_data", BODY_CTX->stageData.scriptDataHash, SIZEOF(BODY_CTX->stageData.scriptDataHash)); - fill_and_display_if_required("Script data hash", encodedStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "script_data", BODY_CTX->stageData.scriptDataHash, SIZEOF(BODY_CTX->stageData.scriptDataHash)); + fill_and_display_if_required("Script data hash", encodedStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_SCRIPT_DATA_HASH_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -753,16 +755,16 @@ void signTx_handleRequiredSigner_ui_runStep() UI_STEP(HANDLE_REQUIRED_SIGNERS_STEP_DISPLAY) { switch (BODY_CTX->stageData.requiredSigner.type) { case REQUIRED_SIGNER_WITH_PATH: -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPathScreen("Required signer", &BODY_CTX->stageData.requiredSigner.keyPath, this_fn); -#elif defined(HAVE_NBGL) - char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; - ui_getPathScreen(pathStr, SIZEOF(pathStr), &BODY_CTX->stageData.requiredSigner.keyPath); - fill_and_display_if_required("Required signer", pathStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; + ui_getPathScreen(pathStr, SIZEOF(pathStr), &BODY_CTX->stageData.requiredSigner.keyPath); + fill_and_display_if_required("Required signer", pathStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL break; case REQUIRED_SIGNER_WITH_HASH: -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayBech32Screen( "Required signer", "req_signer_vkh", @@ -770,11 +772,11 @@ void signTx_handleRequiredSigner_ui_runStep() SIZEOF(BODY_CTX->stageData.requiredSigner.keyHash), this_fn ); -#elif defined(HAVE_NBGL) - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; - ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "req_signer_vfk", BODY_CTX->stageData.requiredSigner.keyHash, SIZEOF(BODY_CTX->stageData.requiredSigner.keyHash)); - fill_and_display_if_required("Required signer", encodedStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "req_signer_vfk", BODY_CTX->stageData.requiredSigner.keyHash, SIZEOF(BODY_CTX->stageData.requiredSigner.keyHash)); + fill_and_display_if_required("Required signer", encodedStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL break; default: @@ -809,13 +811,13 @@ void signTx_handleTotalCollateral_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(HANDLE_TOTAL_COLLATERAL_STEP_DISPLAY) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayAdaAmountScreen("Total collateral", BODY_CTX->stageData.totalCollateral, this_fn); -#elif defined(HAVE_NBGL) - char adaAmountStr[50] = {0}; - ui_getAdaAmountScreen(adaAmountStr, SIZEOF(adaAmountStr), BODY_CTX->stageData.totalCollateral); - fill_and_display_if_required("Total collateral", adaAmountStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char adaAmountStr[50] = {0}; + ui_getAdaAmountScreen(adaAmountStr, SIZEOF(adaAmountStr), BODY_CTX->stageData.totalCollateral); + fill_and_display_if_required("Total collateral", adaAmountStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_TOTAL_COLLATERAL_STEP_RESPOND) { respondSuccessEmptyMsg(); @@ -835,35 +837,35 @@ void signTx_handleConfirm_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(HANDLE_CONFIRM_STEP_TXID) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayHexBufferScreen( "Transaction id", ctx->txHash, SIZEOF(ctx->txHash), this_fn ); -#elif defined(HAVE_NBGL) - char bufferHex[2 * 32 + 1] = {0}; - ui_getHexBufferScreen(bufferHex, SIZEOF(bufferHex), ctx->txHash, SIZEOF(ctx->txHash)); - fill_and_display_if_required("Transaction id", bufferHex, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + char bufferHex[2 * 32 + 1] = {0}; + ui_getHexBufferScreen(bufferHex, SIZEOF(bufferHex), ctx->txHash, SIZEOF(ctx->txHash)); + fill_and_display_if_required("Transaction id", bufferHex, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_CONFIRM_STEP_FINAL_CONFIRM) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPrompt( "Confirm", "transaction?", this_fn, respond_with_user_reject ); -#elif defined(HAVE_NBGL) - display_confirmation("Sign\ntransaction", "", "TRANSACTION\nSIGNED", "Transaction\nrejected", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_confirmation("Sign\ntransaction", "", "TRANSACTION\nSIGNED", "Transaction\nrejected", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { io_send_buf(SUCCESS, ctx->txHash, SIZEOF(ctx->txHash)); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayBusy(); // displays dots, called only after I/O to avoid freezing -#endif // HAVE_BAGL + #endif // HAVE_BAGL tx_advanceStage(); } @@ -888,46 +890,46 @@ void signTx_handleWitness_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(HANDLE_WITNESS_STEP_WARNING) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPaginatedText( "WARNING:", "unusual witness requested", this_fn ); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_warning("Unusual\nwitness requested", this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning("Unusual\nwitness requested", this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_WITNESS_STEP_DISPLAY) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPathScreen("Witness path", &WITNESS_CTX->stageData.witness.path, this_fn); -#elif defined(HAVE_NBGL) - set_light_confirmation(true); - char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; - ui_getPathScreen(pathStr, SIZEOF(pathStr), &WITNESS_CTX->stageData.witness.path); - fill_and_display_if_required("Witness path", pathStr, this_fn, respond_with_user_reject); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; + ui_getPathScreen(pathStr, SIZEOF(pathStr), &WITNESS_CTX->stageData.witness.path); + fill_and_display_if_required("Witness path", pathStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL } UI_STEP(HANDLE_WITNESS_STEP_CONFIRM) { -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayPrompt( "Sign using", "this witness?", this_fn, _wipeWitnessSignature ); -#elif defined(HAVE_NBGL) - display_confirmation("Sign using witness", "", "SIGNATURE\nCONFIRMED", "Signature\nrejected", this_fn, _wipeWitnessSignature); -#endif // HAVE_BAGL + #elif defined(HAVE_NBGL) + display_confirmation("Sign using witness", "", "SIGNATURE\nCONFIRMED", "Signature\nrejected", this_fn, _wipeWitnessSignature); + #endif // HAVE_BAGL } UI_STEP(HANDLE_WITNESS_STEP_RESPOND) { TRACE("Sending witness data"); TRACE_BUFFER(WITNESS_CTX->stageData.witness.signature, SIZEOF(WITNESS_CTX->stageData.witness.signature)); io_send_buf(SUCCESS, WITNESS_CTX->stageData.witness.signature, SIZEOF(WITNESS_CTX->stageData.witness.signature)); -#ifdef HAVE_BAGL + #ifdef HAVE_BAGL ui_displayBusy(); // displays dots, called only after I/O to avoid freezing -#endif // HAVE_BAGL + #endif // HAVE_BAGL WITNESS_CTX->currentWitness++; if (WITNESS_CTX->currentWitness == ctx->numWitnesses) { diff --git a/src/ui.h b/src/ui.h index 85a7a578..46b16bd2 100644 --- a/src/ui.h +++ b/src/ui.h @@ -9,7 +9,7 @@ typedef void (*callback_t)(void); void set_light_confirmation(bool needed); void display_address(callback_t user_accept_cb, callback_t user_reject_cb); -void fill_address_data(char* text, char *content); +void fill_address_data(char* text, char* content); void fill_and_display_if_required(const char* line1, const char* line2, callback_t user_accept_cb, callback_t user_reject_cb); void fill_and_display_new_page(const char* line1, const char* line2, callback_t user_accept_cb, callback_t user_reject_cb); void force_display(callback_t user_accept_cb, callback_t user_reject_cb); @@ -22,10 +22,10 @@ void ui_idle_flow(void); void display_cancel_message(void); void display_error(void); void nbgl_reset_transaction_full_context(void); -#endif +#endif #ifdef HAVE_BAGL -void io_seproxyhal_display(const bagl_element_t *element); +void io_seproxyhal_display(const bagl_element_t* element); #endif // HAVE_BAGL #endif // H_CARDANO_APP_UI_H diff --git a/src/uiScreens_nbgl.c b/src/uiScreens_nbgl.c index d781abd7..e11ca73d 100644 --- a/src/uiScreens_nbgl.c +++ b/src/uiScreens_nbgl.c @@ -97,14 +97,14 @@ void ui_getPublicKeyType( { switch (bip44_classifyPath(path)) { case PATH_POOL_COLD_KEY: { - strncpy(line, "Export\nCold public key", lineSize); + strncpy(line, "Export\nCold public key", lineSize); return; } - case PATH_ORDINARY_ACCOUNT: - // Fallthrough - default: - strncpy(line, "Export\nPublic key", lineSize); + case PATH_ORDINARY_ACCOUNT: + // Fallthrough + default: + strncpy(line, "Export\nPublic key", lineSize); return; } } @@ -121,27 +121,27 @@ void ui_getPublicKeyPathScreen( { switch (bip44_classifyPath(path)) { case PATH_POOL_COLD_KEY: { - strncpy(line1, "Cold public key", line1Size); + strncpy(line1, "Cold public key", line1Size); ui_getPathScreen( - line2, - line2Size, + line2, + line2Size, path ); return; } case PATH_ORDINARY_ACCOUNT: { - strncpy(line1, "Public key", line1Size); + strncpy(line1, "Public key", line1Size); _ui_getAccountWithDescriptionScreen(line2, line2Size, path); return; } default: - strncpy(line1, "Public key", line1Size); + strncpy(line1, "Public key", line1Size); ui_getPathScreen( - line2, - line2Size, + line2, + line2Size, path ); return; @@ -159,8 +159,8 @@ void ui_getStakingKeyScreen( explicit_bzero(line, lineSize); _ui_getAccountWithDescriptionScreen( - line, - lineSize, + line, + lineSize, stakingPath ); } @@ -171,37 +171,37 @@ void ui_getAccountScreeen( char* line2, const size_t line2Size, const bip44_path_t* path -) +) { explicit_bzero(line1, line1Size); explicit_bzero(line2, line2Size); - uint32_t account = unharden(bip44_getAccount(path)); - STATIC_ASSERT(sizeof(account + 1) <= sizeof(unsigned), "oversized type for %u"); - STATIC_ASSERT(!IS_SIGNED(account + 1), "signed type for %u"); - if (bip44_hasByronPrefix(path)) { - snprintf( - line1, line1Size, - "Byron account" - ); - snprintf( - line2, line2Size, - "#%u", - account + 1 - ); - } else if (bip44_hasShelleyPrefix(path)) { - snprintf( - line1, line1Size, - "Account" - ); - snprintf( - line2, line2Size, - "#%u", - account + 1 - ); - } else { - ASSERT(false); - } + uint32_t account = unharden(bip44_getAccount(path)); + STATIC_ASSERT(sizeof(account + 1) <= sizeof(unsigned), "oversized type for %u"); + STATIC_ASSERT(!IS_SIGNED(account + 1), "signed type for %u"); + if (bip44_hasByronPrefix(path)) { + snprintf( + line1, line1Size, + "Byron account" + ); + snprintf( + line2, line2Size, + "#%u", + account + 1 + ); + } else if (bip44_hasShelleyPrefix(path)) { + snprintf( + line1, line1Size, + "Account" + ); + snprintf( + line2, line2Size, + "#%u", + account + 1 + ); + } else { + ASSERT(false); + } } // bech32 for Shelley, base58 for Byron @@ -264,9 +264,9 @@ static void _getRewardAccountWithDescriptionScreen( // displays bech32-encoded reward account preceded by path (if given) void ui_getRewardAccountScreen( - char *firstLine, + char* firstLine, const size_t firstLineSize, - char *secondLine, + char* secondLine, const size_t secondLineSize, const reward_account_t* rewardAccount, uint8_t networkId @@ -326,8 +326,8 @@ void ui_getRewardAccountScreen( } _getRewardAccountWithDescriptionScreen( - secondLine, - secondLineSize, + secondLine, + secondLineSize, rewardAccount->keyReferenceType, &rewardAccount->path, rewardAccountBuffer @@ -335,9 +335,9 @@ void ui_getRewardAccountScreen( } void ui_getSpendingInfoScreen( - char *line1, + char* line1, const size_t line1Size, - char *line2, + char* line2, const size_t line2Size, const addressParams_t* addressParams ) @@ -345,20 +345,20 @@ void ui_getSpendingInfoScreen( switch (determineSpendingChoice(addressParams->type)) { case SPENDING_PATH: { - snprintf(line1, line1Size, "Spending path"); + snprintf(line1, line1Size, "Spending path"); ui_getPathScreen( - line2, - line2Size, + line2, + line2Size, &addressParams->spendingKeyPath ); return; } case SPENDING_SCRIPT_HASH: { - snprintf(line1, line1Size, "Spending script hash"); + snprintf(line1, line1Size, "Spending script hash"); ui_getBech32Screen( - line2, - line2Size, + line2, + line2Size, "script", addressParams->spendingScriptHash, SIZEOF(addressParams->spendingScriptHash) @@ -380,9 +380,9 @@ static const char STAKING_HEADING_POINTER[] = "Staking key pointer"; static const char STAKING_HEADING_WARNING[] = "WARNING:"; void ui_getStakingInfoScreen( - char* line1, + char* line1, const size_t line1Size, - char* line2, + char* line2, const size_t line2Size, const addressParams_t* addressParams ) @@ -412,13 +412,13 @@ void ui_getStakingInfoScreen( } case STAKING_KEY_PATH: { - strncpy(line1, STAKING_HEADING_PATH, line1Size); + strncpy(line1, STAKING_HEADING_PATH, line1Size); bip44_printToStr(&addressParams->stakingKeyPath, line2, line2Size); break; } case STAKING_KEY_HASH: { - strncpy(line1, STAKING_HEADING_KEY_HASH, line1Size); + strncpy(line1, STAKING_HEADING_KEY_HASH, line1Size); bech32_encode( "stake_vkh", // shared keys never go into address directly addressParams->stakingKeyHash, SIZEOF(addressParams->stakingKeyHash), @@ -428,7 +428,7 @@ void ui_getStakingInfoScreen( } case STAKING_SCRIPT_HASH: { - strncpy(line1, STAKING_HEADING_SCRIPT_HASH, line1Size); + strncpy(line1, STAKING_HEADING_SCRIPT_HASH, line1Size); bech32_encode( "script", addressParams->stakingScriptHash, SIZEOF(addressParams->stakingScriptHash), @@ -438,7 +438,7 @@ void ui_getStakingInfoScreen( } case BLOCKCHAIN_POINTER: - strncpy(line1, STAKING_HEADING_POINTER, line1Size); + strncpy(line1, STAKING_HEADING_POINTER, line1Size); printBlockchainPointerToStr(addressParams->stakingKeyBlockchainPointer, line2, line2Size); break; @@ -453,7 +453,7 @@ void ui_getStakingInfoScreen( } void ui_getAssetFingerprintScreen( - char* line, + char* line, const size_t lineSize, const token_group_t* tokenGroup, const uint8_t* assetNameBytes, size_t assetNameSize @@ -482,7 +482,7 @@ void ui_getAdaAmountScreen( } void ui_getTokenAmountOutputScreen( - char* line, + char* line, const size_t lineSize, const token_group_t* tokenGroup, const uint8_t* assetNameBytes, size_t assetNameSize, @@ -549,7 +549,7 @@ void ui_getValidityBoundaryScreen( } else { ui_getUint64Screen( line, - lineSize, + lineSize, boundary ); } @@ -594,7 +594,7 @@ void ui_getNetworkParamsScreen_2( } void ui_getPoolMarginScreen( - char* line1, size_t lineSize, + char* line1, size_t lineSize, uint64_t marginNumerator, uint64_t marginDenominator ) { @@ -622,7 +622,7 @@ void ui_getPoolMarginScreen( } void ui_getPoolOwnerScreen( - char* firstLine, + char* firstLine, const size_t firstLineSize, char* secondLine, const size_t secondLineSize, @@ -670,8 +670,8 @@ void ui_getPoolOwnerScreen( ASSERT(strlen(firstLine) + 1 < firstLineSize); _getRewardAccountWithDescriptionScreen( - secondLine, - secondLineSize, + secondLine, + secondLineSize, owner->keyReferenceType, &owner->path, rewardAddress diff --git a/src/uiScreens_nbgl.h b/src/uiScreens_nbgl.h index ea79a59e..a11316f9 100644 --- a/src/uiScreens_nbgl.h +++ b/src/uiScreens_nbgl.h @@ -65,9 +65,9 @@ void ui_getAccountScreeen( __noinline_due_to_stack__ void ui_getRewardAccountScreen( - char *firstLine, + char* firstLine, const size_t firstLineSize, - char *secondLine, + char* secondLine, const size_t secondLineSize, const reward_account_t* rewardAccount, uint8_t networkId @@ -75,25 +75,25 @@ void ui_getRewardAccountScreen( __noinline_due_to_stack__ void ui_getSpendingInfoScreen( - char *line1, + char* line1, const size_t line1Size, - char *line2, + char* line2, const size_t line2Size, const addressParams_t* addressParams ); __noinline_due_to_stack__ void ui_getStakingInfoScreen( - char* line1, + char* line1, const size_t line1Size, - char* line2, + char* line2, const size_t line2Size, const addressParams_t* addressParams ); __noinline_due_to_stack__ void ui_getAssetFingerprintScreen( - char* line, + char* line, const size_t lineSize, const token_group_t* tokenGroup, const uint8_t* assetNameBytes, size_t assetNameSize @@ -108,7 +108,7 @@ void ui_getAdaAmountScreen( __noinline_due_to_stack__ void ui_getTokenAmountOutputScreen( - char* line, + char* line, const size_t lineSize, const token_group_t* tokenGroup, const uint8_t* assetNameBytes, size_t assetNameSize, @@ -161,13 +161,13 @@ void ui_getNetworkParamsScreen_2( __noinline_due_to_stack__ void ui_getPoolMarginScreen( - char* line1, const size_t lineSize, + char* line1, const size_t lineSize, uint64_t marginNumerator, uint64_t marginDenominator ); __noinline_due_to_stack__ void ui_getPoolOwnerScreen( - char* firstLine, + char* firstLine, const size_t firstLineSize, char* secondLine, const size_t secondLineSize, From a0b94787a90729a398aa0acc7cdac98f81e7e3e5 Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Sun, 12 Mar 2023 22:59:56 +0100 Subject: [PATCH 028/105] fix: missing HAVE_NBGL --- src/signTxPoolRegistration_ui.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/signTxPoolRegistration_ui.c b/src/signTxPoolRegistration_ui.c index d0087f67..8c974e6f 100644 --- a/src/signTxPoolRegistration_ui.c +++ b/src/signTxPoolRegistration_ui.c @@ -335,9 +335,12 @@ void handlePoolFinancials_ui_runStep() // ============================== POOL REWARD ACCOUNT ============================== -static void handlePoolRewardAccount_ui_runStep_cb(void) { +#ifdef HAVE_NBGL +static void handlePoolRewardAccount_ui_runStep_cb(void) +{ force_display(handlePoolRewardAccount_ui_runStep, respond_with_user_reject); } +#endif void handlePoolRewardAccount_ui_runStep() { From 8e7a25461f3c880849124c4b1065e60b361f04e8 Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Sun, 12 Mar 2023 23:25:05 +0100 Subject: [PATCH 029/105] fix: main.c exception handling --- src/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main.c b/src/main.c index a71d7132..03e9a451 100644 --- a/src/main.c +++ b/src/main.c @@ -162,6 +162,8 @@ static void cardano_main(void) ui_idle(); display_error(); } + #else + ui_idle(); #endif } else { PRINTF("Uncaught error 0x%x", (unsigned) e); From 334892e0a41533b6555256efe17a838b3e05a318 Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Mon, 13 Mar 2023 00:16:40 +0100 Subject: [PATCH 030/105] fix: pointer warning --- src/deriveNativeScriptHash_ui.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/deriveNativeScriptHash_ui.c b/src/deriveNativeScriptHash_ui.c index b07631b3..9c534a48 100644 --- a/src/deriveNativeScriptHash_ui.c +++ b/src/deriveNativeScriptHash_ui.c @@ -13,7 +13,7 @@ static ins_derive_native_script_hash_context_t* ctx = &(instructionState.deriveNativeScriptHashContext); // UI -typedef char* charPtr; +typedef const char* charPtr; const charPtr ui_native_script_header[7] = {"Script - key path", "Script - key", "Script - ALL", "Script - ANY", "Script - N of K", "Script - invalid before", "Script - invalid hereafter"}; #define ASSERT_UI_SCRIPT_TYPE_SANITY() ASSERT(ctx->ui_scriptType >= UI_SCRIPT_PUBKEY_PATH && ctx->ui_scriptType <= UI_SCRIPT_INVALID_HEREAFTER) From d7b4ba3e47d38735525a63be2dbbd7118bb743bc Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Tue, 7 Mar 2023 14:54:42 +0100 Subject: [PATCH 031/105] refactor: deriveAddress.c --- src/deriveAddress.c | 315 +++++++++++++++++++++++++------------------- 1 file changed, 176 insertions(+), 139 deletions(-) diff --git a/src/deriveAddress.c b/src/deriveAddress.c index 36dae829..09f2f5c9 100644 --- a/src/deriveAddress.c +++ b/src/deriveAddress.c @@ -23,7 +23,6 @@ enum { P1_DISPLAY = 0x02, }; - void deriveAddress_response(void) { ctx->responseReadyMagic = 0; @@ -32,6 +31,7 @@ void deriveAddress_response(void) io_send_buf(SUCCESS, ctx->address.buffer, ctx->address.size); ui_idle(); } + static void prepareResponse() { ctx->address.size = deriveAddress( @@ -41,6 +41,86 @@ static void prepareResponse() ctx->responseReadyMagic = RESPONSE_READY_MAGIC; } +/* ========================== RETURN ADDRESS ========================== */ + +static void _displayUnusualRequestWarning(ui_callback_fn_t* this_fn) +{ + #ifdef HAVE_BAGL + ui_displayPaginatedText( + "Unusual request", + "Proceed with care", + this_fn + ); + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning( + "Unusual request", + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL +} + +static void _displayExportAddress(ui_callback_fn_t* this_fn) +{ + #ifdef HAVE_BAGL + ui_displayPaginatedText("Export", "address", this_fn); + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_prompt( + "Export address", + "", + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL +} + +static void _displaySpendingInfo_returnAddr(ui_callback_fn_t* this_fn) +{ + #ifdef HAVE_BAGL + ui_displaySpendingInfoScreen(&ctx->addressParams, this_fn); + #elif defined(HAVE_NBGL) +#define SPENDING_INFO_SIZE MAX(11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX, 2 * BECH32_BUFFER_SIZE_MAX) + char line1[30] = {0}; + char spendingInfo[SPENDING_INFO_SIZE] = {0}; + ui_getSpendingInfoScreen(line1, SIZEOF(line1), spendingInfo, SIZEOF(spendingInfo), &ctx->addressParams); + fill_and_display_if_required(line1, spendingInfo, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL +} + +static void _displayStakingInfo_returnAddr(ui_callback_fn_t* this_fn) +{ + #ifdef HAVE_BAGL + ui_displayStakingInfoScreen(&ctx->addressParams, this_fn); + #elif defined(HAVE_NBGL) + char line1[30] = {0}; + char stakingInfo[120] = {0}; + ui_getStakingInfoScreen(line1, SIZEOF(line1), stakingInfo, SIZEOF(stakingInfo), &ctx->addressParams); + fill_and_display_if_required(line1, stakingInfo, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL +} + +static void _displayConfirmExportAddressPrompt(ui_callback_fn_t* this_fn) +{ + #ifdef HAVE_BAGL + ui_displayPrompt( + "Confirm", + "export address?", + this_fn, + respond_with_user_reject + ); + #elif defined(HAVE_NBGL) + display_confirmation( + "Confirm\n address export", + "", + "ADDRESS\nEXPORTED", + "Address\nrejected", + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL +} static void deriveAddress_return_ui_runStep(); enum { @@ -83,77 +163,23 @@ static void deriveAddress_return_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(RETURN_UI_STEP_WARNING) { - #ifdef HAVE_BAGL - ui_displayPaginatedText( - "Unusual request", - "Proceed with care", - this_fn - ); - #elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_warning( - "Unusual request", - this_fn, - respond_with_user_reject - ); - #endif // HAVE_BAGL + _displayUnusualRequestWarning(this_fn); } UI_STEP(RETURN_UI_STEP_BEGIN) { - #ifdef HAVE_BAGL - ui_displayPaginatedText("Export", "address", this_fn); - #elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_prompt( - "Export address", - "", - this_fn, - respond_with_user_reject - ); - #endif // HAVE_BAGL + _displayExportAddress(this_fn); } UI_STEP(RETURN_UI_STEP_SPENDING_PATH) { if (determineSpendingChoice(ctx->addressParams.type) == SPENDING_NONE) { // reward address UI_STEP_JUMP(RETURN_UI_STEP_STAKING_INFO); } - #ifdef HAVE_BAGL - ui_displaySpendingInfoScreen(&ctx->addressParams, this_fn); - #elif defined(HAVE_NBGL) -#define SPENDING_INFO_SIZE MAX(11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX, 2 * BECH32_BUFFER_SIZE_MAX) - char line1[30]; - char spendingInfo[SPENDING_INFO_SIZE] = {0}; - ui_getSpendingInfoScreen(line1, SIZEOF(line1), spendingInfo, SIZEOF(spendingInfo), &ctx->addressParams); - fill_and_display_if_required(line1, spendingInfo, this_fn, respond_with_user_reject); - #endif // HAVE_BAGL + _displaySpendingInfo_returnAddr(this_fn); } UI_STEP(RETURN_UI_STEP_STAKING_INFO) { - #ifdef HAVE_BAGL - ui_displayStakingInfoScreen(&ctx->addressParams, this_fn); - #elif defined(HAVE_NBGL) - char line1[30] = {0}; - char stakingInfo[120] = {0}; - ui_getStakingInfoScreen(line1, SIZEOF(line1), stakingInfo, SIZEOF(stakingInfo), &ctx->addressParams); - fill_and_display_if_required(line1, stakingInfo, this_fn, respond_with_user_reject); - #endif // HAVE_BAGL + _displayStakingInfo_returnAddr(this_fn); } UI_STEP(RETURN_UI_STEP_CONFIRM) { - #ifdef HAVE_BAGL - ui_displayPrompt( - "Confirm", - "export address?", - this_fn, - respond_with_user_reject - ); - #elif defined(HAVE_NBGL) - display_confirmation( - "Confirm\n address export", - "", - "ADDRESS\nEXPORTED", - "Address\nrejected", - this_fn, - respond_with_user_reject - ); - #endif // HAVE_BAGL + _displayConfirmExportAddressPrompt(this_fn); } UI_STEP(RETURN_UI_STEP_RESPOND) { ctx->responseReadyMagic = 0; @@ -165,6 +191,88 @@ static void deriveAddress_return_ui_runStep() UI_STEP_END(RETURN_UI_STEP_INVALID); } +/* ========================== DISPLAY ADDRESS ========================== */ + +static void _displayVerifyAddressMsg(ui_callback_fn_t* this_fn) +{ + #ifdef HAVE_BAGL + ui_displayPaginatedText( + "Verify address", + "Make sure it agrees with your computer", + this_fn + ); + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning( + "Make sure address matches\nwith your computer", + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL +} + +static void _displaySpendingInfo_displayAddr(ui_callback_fn_t* this_fn) +{ + #ifdef HAVE_BAGL + ui_displaySpendingInfoScreen(&ctx->addressParams, this_fn); + #elif defined(HAVE_NBGL) +#define SPENDING_INFO_SIZE MAX(11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX, 2 * BECH32_BUFFER_SIZE_MAX) + char line1[30] = {0}; + char spendingInfo[SPENDING_INFO_SIZE] = {0}; + ui_getSpendingInfoScreen(line1, SIZEOF(line1), spendingInfo, SIZEOF(spendingInfo), &ctx->addressParams); + fill_address_data(line1, spendingInfo); + #endif // HAVE_BAGL +} + +static void _displayStakingInfo_displayAddr(ui_callback_fn_t* this_fn) +{ + #ifdef HAVE_BAGL + ui_displayStakingInfoScreen(&ctx->addressParams, this_fn); + #elif defined(HAVE_NBGL) + char line1[30] = {0}; + char stakingInfo[120] = {0}; + ui_getStakingInfoScreen(line1, SIZEOF(line1), stakingInfo, SIZEOF(stakingInfo), &ctx->addressParams); + fill_address_data(line1, stakingInfo); + #endif // HAVE_BAGL +} + +static void _displayAddress(ui_callback_fn_t* this_fn) +{ + ASSERT(ctx->address.size <= SIZEOF(ctx->address.buffer)); + #ifdef HAVE_BAGL + ui_displayAddressScreen( + "Address", + ctx->address.buffer, ctx->address.size, + this_fn + ); + #elif defined(HAVE_NBGL) + char humanAddress[MAX_HUMAN_ADDRESS_SIZE] = {0}; + ui_getAddressScreen( + humanAddress, + SIZEOF(humanAddress), + ctx->address.buffer, + ctx->address.size + ); + fill_address_data((char*)"Address", humanAddress); + #endif // HAVE_BAGL +} + +static void _displayConfirmAddressPrompt(ui_callback_fn_t* this_fn) +{ + #ifdef HAVE_BAGL + ui_displayPrompt( + "Confirm", + "address?", + this_fn, + respond_with_user_reject + ); + #elif defined(HAVE_NBGL) + display_address( + this_fn, + respond_with_user_reject + ); + #endif // HAVE_BAGL +} static void deriveAddress_display_ui_runStep(); enum { @@ -178,7 +286,6 @@ enum { DISPLAY_UI_STEP_INVALID }; - static void deriveAddress_handleDisplay() { // Check security policy @@ -207,98 +314,26 @@ static void deriveAddress_display_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(DISPLAY_UI_STEP_WARNING) { - #ifdef HAVE_BAGL - ui_displayPaginatedText( - "Unusual request", - "Proceed with care", - this_fn - ); - #elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_warning( - "Unusual request", - this_fn, - respond_with_user_reject - ); - #endif // HAVE_BAGL + _displayUnusualRequestWarning(this_fn); } UI_STEP(DISPLAY_UI_STEP_INSTRUCTIONS) { - #ifdef HAVE_BAGL - ui_displayPaginatedText( - "Verify address", - "Make sure it agrees with your computer", - this_fn - ); - #elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_warning( - "Make sure address matches\nwith your computer", - this_fn, - respond_with_user_reject - ); - #endif // HAVE_BAGL + _displayVerifyAddressMsg(this_fn); } UI_STEP(DISPLAY_UI_STEP_SPENDING_INFO) { if (determineSpendingChoice(ctx->addressParams.type) == SPENDING_NONE) { // reward address UI_STEP_JUMP(DISPLAY_UI_STEP_STAKING_INFO); } - #ifdef HAVE_BAGL - ui_displaySpendingInfoScreen(&ctx->addressParams, this_fn); - #elif defined(HAVE_NBGL) -#define SPENDING_INFO_SIZE MAX(11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX, 2 * BECH32_BUFFER_SIZE_MAX) - char line1[30] = {0}; - char spendingInfo[SPENDING_INFO_SIZE] = {0}; - ui_getSpendingInfoScreen(line1, SIZEOF(line1), spendingInfo, SIZEOF(spendingInfo), &ctx->addressParams); - fill_address_data(line1, spendingInfo); - UI_STEP_JUMP(DISPLAY_UI_STEP_STAKING_INFO); - #endif // HAVE_BAGL + _displaySpendingInfo_displayAddr(this_fn); } UI_STEP(DISPLAY_UI_STEP_STAKING_INFO) { - #ifdef HAVE_BAGL - ui_displayStakingInfoScreen(&ctx->addressParams, this_fn); - #elif defined(HAVE_NBGL) - char line1[30] = {0}; - char stakingInfo[120] = {0}; - ui_getStakingInfoScreen(line1, SIZEOF(line1), stakingInfo, SIZEOF(stakingInfo), &ctx->addressParams); - fill_address_data(line1, stakingInfo); - UI_STEP_JUMP(DISPLAY_UI_STEP_ADDRESS); - #endif // HAVE_BAGL + _displayStakingInfo_displayAddr(this_fn); } UI_STEP(DISPLAY_UI_STEP_ADDRESS) { - ASSERT(ctx->address.size <= SIZEOF(ctx->address.buffer)); - #ifdef HAVE_BAGL - ui_displayAddressScreen( - "Address", - ctx->address.buffer, ctx->address.size, - this_fn - ); - #elif defined(HAVE_NBGL) - char humanAddress[MAX_HUMAN_ADDRESS_SIZE] = {0}; - ui_getAddressScreen( - humanAddress, - SIZEOF(humanAddress), - ctx->address.buffer, - ctx->address.size - ); - fill_address_data((char*)"Address", humanAddress); - UI_STEP_JUMP(DISPLAY_UI_STEP_CONFIRM) - #endif // HAVE_BAGL + _displayAddress(this_fn); } UI_STEP(DISPLAY_UI_STEP_CONFIRM) { - #ifdef HAVE_BAGL - ui_displayPrompt( - "Confirm", - "address?", - this_fn, - respond_with_user_reject - ); - #elif defined(HAVE_NBGL) - display_address( - this_fn, - respond_with_user_reject - ); - #endif // HAVE_BAGL + _displayConfirmAddressPrompt(this_fn); } UI_STEP(DISPLAY_UI_STEP_RESPOND) { io_send_buf(SUCCESS, NULL, 0); @@ -307,6 +342,8 @@ static void deriveAddress_display_ui_runStep() UI_STEP_END(DISPLAY_UI_STEP_INVALID); } +/* ========================== TOP-LEVEL HANDLER ========================== */ + void deriveAddress_handleAPDU( uint8_t p1, uint8_t p2, From 4c65af548650cb1dcddeffeae0b5517b410b1b00 Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Mon, 13 Mar 2023 12:17:14 +0100 Subject: [PATCH 032/105] refactor: common unusual req. warning --- src/deriveAddress.c | 22 ++-------------------- src/getPublicKeys_ui.c | 15 +-------------- src/signOpCert.c | 14 +------------- src/signTxCVoteRegistration_ui.c | 22 ++-------------------- src/uiHelpers.c | 20 +++++++++++++++++++- src/uiHelpers.h | 2 ++ 6 files changed, 27 insertions(+), 68 deletions(-) diff --git a/src/deriveAddress.c b/src/deriveAddress.c index 09f2f5c9..3a3954ce 100644 --- a/src/deriveAddress.c +++ b/src/deriveAddress.c @@ -43,24 +43,6 @@ static void prepareResponse() /* ========================== RETURN ADDRESS ========================== */ -static void _displayUnusualRequestWarning(ui_callback_fn_t* this_fn) -{ - #ifdef HAVE_BAGL - ui_displayPaginatedText( - "Unusual request", - "Proceed with care", - this_fn - ); - #elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_warning( - "Unusual request", - this_fn, - respond_with_user_reject - ); - #endif // HAVE_BAGL -} - static void _displayExportAddress(ui_callback_fn_t* this_fn) { #ifdef HAVE_BAGL @@ -163,7 +145,7 @@ static void deriveAddress_return_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(RETURN_UI_STEP_WARNING) { - _displayUnusualRequestWarning(this_fn); + ui_displayUnusualWarning(this_fn); } UI_STEP(RETURN_UI_STEP_BEGIN) { _displayExportAddress(this_fn); @@ -314,7 +296,7 @@ static void deriveAddress_display_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(DISPLAY_UI_STEP_WARNING) { - _displayUnusualRequestWarning(this_fn); + ui_displayUnusualWarning(this_fn); } UI_STEP(DISPLAY_UI_STEP_INSTRUCTIONS) { _displayVerifyAddressMsg(this_fn); diff --git a/src/getPublicKeys_ui.c b/src/getPublicKeys_ui.c index 07f65fd3..eb4255bb 100644 --- a/src/getPublicKeys_ui.c +++ b/src/getPublicKeys_ui.c @@ -71,20 +71,7 @@ void getPublicKeys_respondOneKey_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(GET_KEY_UI_STEP_WARNING) { - #ifdef HAVE_BAGL - ui_displayPaginatedText( - "Unusual request", - "Proceed with care", - this_fn - ); - #elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_warning( - "Unusual request", - this_fn, - respond_with_user_reject - ); - #endif // HAVE_BAGL + ui_displayUnusualWarning(this_fn); } UI_STEP(GET_KEY_UI_STEP_PROMPT) { #ifdef HAVE_BAGL diff --git a/src/signOpCert.c b/src/signOpCert.c index ee108419..493b15e1 100644 --- a/src/signOpCert.c +++ b/src/signOpCert.c @@ -135,19 +135,7 @@ static void signOpCert_ui_runStep() UI_STEP_BEGIN(ctx->ui_step, this_fn); UI_STEP(UI_STEP_WARNING) { - #ifdef HAVE_BAGL - ui_displayPaginatedText( - "Unusual request", - "Proceed with care", - this_fn - ); - #elif defined(HAVE_NBGL) - display_warning( - "Unusual request", - this_fn, - respond_with_user_reject - ); - #endif // HAVE_BAGL + ui_displayUnusualWarning(this_fn); } UI_STEP(UI_STEP_CONFIRM_START) { #ifdef HAVE_BAGL diff --git a/src/signTxCVoteRegistration_ui.c b/src/signTxCVoteRegistration_ui.c index 468d6d89..bebf957d 100644 --- a/src/signTxCVoteRegistration_ui.c +++ b/src/signTxCVoteRegistration_ui.c @@ -171,16 +171,7 @@ void signTxCVoteRegistration_handleStakingKey_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_STAKING_KEY_STEP_WARNING) { - #ifdef HAVE_BAGL - ui_displayPaginatedText( - "Unusual request", - "Proceed with care", - this_fn - ); - #elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_warning("Unusual request\nProceed with care", this_fn, respond_with_user_reject); - #endif // HAVE_BAGL + ui_displayUnusualWarning(this_fn); } UI_STEP(HANDLE_STAKING_KEY_STEP_DISPLAY) { #ifdef HAVE_BAGL @@ -225,16 +216,7 @@ void signTxCVoteRegistration_handlePaymentAddress_ui_runStep() UI_STEP_BEGIN(subctx->ui_step, this_fn); UI_STEP(HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_WARNING) { - #ifdef HAVE_BAGL - ui_displayPaginatedText( - "Unusual request", - "Proceed with care", - this_fn - ); - #elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_warning("Unusual request\nProceed with care", this_fn, respond_with_user_reject); - #endif // HAVE_BAGL + ui_displayUnusualWarning(this_fn); } UI_STEP(HANDLE_PAYMENT_ADDRESS_PARAMS_STEP_DISPLAY_ADDRESS) { uint8_t addressBuffer[MAX_ADDRESS_SIZE] = {0}; diff --git a/src/uiHelpers.c b/src/uiHelpers.c index 60bccbcf..926d49e1 100644 --- a/src/uiHelpers.c +++ b/src/uiHelpers.c @@ -218,7 +218,25 @@ void ui_displayPaginatedText( } #endif // HEADLESS } -#endif +#endif // HAVE_BAGL + +void ui_displayUnusualWarning(ui_callback_fn_t* cb) +{ + #ifdef HAVE_BAGL + ui_displayPaginatedText( + "Unusual request", + "Proceed with care", + cb + ); + #elif defined(HAVE_NBGL) + set_light_confirmation(true); + display_warning( + "Unusual request\nProceed with care", + cb, + respond_with_user_reject + ); + #endif // HAVE_BAGL +} void respond_with_user_reject() { diff --git a/src/uiHelpers.h b/src/uiHelpers.h index 5c58f5aa..b9a9bcbd 100644 --- a/src/uiHelpers.h +++ b/src/uiHelpers.h @@ -124,6 +124,8 @@ void ui_displayPrompt( ui_callback_fn_t* reject ); +void ui_displayUnusualWarning(ui_callback_fn_t* cb); + void ui_displayBusy(); void ui_displayPrompt_run(); void ui_displayPaginatedText_run(); From df83e5e6391a0621e49ca27b326b7dc7ab584757 Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Mon, 13 Mar 2023 12:34:25 +0100 Subject: [PATCH 033/105] fix: spending info buffer size --- src/bech32.h | 1 + src/deriveAddress.c | 4 ++-- src/deriveNativeScriptHash_ui.c | 4 ++-- src/signOpCert.c | 6 +++--- src/signTxCVoteRegistration_ui.c | 2 +- src/signTxOutput_ui.c | 4 ++-- src/signTxPoolRegistration_ui.c | 4 ++-- src/signTx_ui.c | 12 ++++++------ src/uiScreens_bagl.c | 2 +- 9 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/bech32.h b/src/bech32.h index 16ceb881..0baaf005 100644 --- a/src/bech32.h +++ b/src/bech32.h @@ -7,6 +7,7 @@ #define BECH32_BUFFER_SIZE_MAX 150 #define BECH32_PREFIX_LENGTH_MAX 16 +#define BECH32_STRING_SIZE_MAX (1 + 11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX) /* * Encode bytes, using human-readable prefix given in hrp. diff --git a/src/deriveAddress.c b/src/deriveAddress.c index 3a3954ce..ff224230 100644 --- a/src/deriveAddress.c +++ b/src/deriveAddress.c @@ -63,7 +63,7 @@ static void _displaySpendingInfo_returnAddr(ui_callback_fn_t* this_fn) #ifdef HAVE_BAGL ui_displaySpendingInfoScreen(&ctx->addressParams, this_fn); #elif defined(HAVE_NBGL) -#define SPENDING_INFO_SIZE MAX(11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX, 2 * BECH32_BUFFER_SIZE_MAX) +#define SPENDING_INFO_SIZE MAX(BECH32_STRING_SIZE_MAX, BIP44_PATH_STRING_SIZE_MAX) char line1[30] = {0}; char spendingInfo[SPENDING_INFO_SIZE] = {0}; ui_getSpendingInfoScreen(line1, SIZEOF(line1), spendingInfo, SIZEOF(spendingInfo), &ctx->addressParams); @@ -198,7 +198,7 @@ static void _displaySpendingInfo_displayAddr(ui_callback_fn_t* this_fn) #ifdef HAVE_BAGL ui_displaySpendingInfoScreen(&ctx->addressParams, this_fn); #elif defined(HAVE_NBGL) -#define SPENDING_INFO_SIZE MAX(11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX, 2 * BECH32_BUFFER_SIZE_MAX) +#define SPENDING_INFO_SIZE MAX(BECH32_STRING_SIZE_MAX, BIP44_PATH_STRING_SIZE_MAX) char line1[30] = {0}; char spendingInfo[SPENDING_INFO_SIZE] = {0}; ui_getSpendingInfoScreen(line1, SIZEOF(line1), spendingInfo, SIZEOF(spendingInfo), &ctx->addressParams); diff --git a/src/deriveNativeScriptHash_ui.c b/src/deriveNativeScriptHash_ui.c index 9c534a48..627a8b4b 100644 --- a/src/deriveNativeScriptHash_ui.c +++ b/src/deriveNativeScriptHash_ui.c @@ -179,7 +179,7 @@ void deriveScriptHash_display_ui_runStep() this_fn ); #elif defined(HAVE_NBGL) - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + char encodedStr[BECH32_STRING_SIZE_MAX] = {0}; ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "addr_shared_vkh", ctx->scriptContent.pubkeyHash, ADDRESS_KEY_HASH_LENGTH); fill_and_display_if_required("Pubkey hash", encodedStr, this_fn, respond_with_user_reject); #endif // HAVE_BAGL @@ -316,7 +316,7 @@ void deriveNativeScriptHash_displayNativeScriptHash_bech32() deriveNativeScriptHash_displayNativeScriptHash_callback ); #elif defined(HAVE_NBGL) - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + char encodedStr[BECH32_STRING_SIZE_MAX] = {0}; ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "script", ctx->scriptHashBuffer, SCRIPT_HASH_LENGTH); fill_and_display_if_required("Script hash", encodedStr, deriveNativeScriptHash_displayNativeScriptHash_finish, respond_with_user_reject); #endif // HAVE_BAGL diff --git a/src/signOpCert.c b/src/signOpCert.c index 493b15e1..9a3302b4 100644 --- a/src/signOpCert.c +++ b/src/signOpCert.c @@ -147,7 +147,7 @@ static void signOpCert_ui_runStep() ); #elif defined(HAVE_NBGL) display_prompt( - "Start new\noperational certificate", + "Start new\noperational certificate?", "", this_fn, respond_with_user_reject @@ -175,7 +175,7 @@ static void signOpCert_ui_runStep() this_fn ); #elif defined(HAVE_NBGL) - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + char encodedStr[BECH32_STRING_SIZE_MAX] = {0}; ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "pool", poolKeyHash, SIZEOF(poolKeyHash)); fill_and_display_if_required("Pool ID", encodedStr, this_fn, respond_with_user_reject); #endif // HAVE_BAGL @@ -189,7 +189,7 @@ static void signOpCert_ui_runStep() this_fn ); #elif defined(HAVE_NBGL) - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + char encodedStr[BECH32_STRING_SIZE_MAX] = {0}; ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "kes_vk", ctx->kesPublicKey, SIZEOF(ctx->kesPublicKey)); fill_and_display_if_required("KES public key", encodedStr, this_fn, respond_with_user_reject); #endif // HAVE_BAGL diff --git a/src/signTxCVoteRegistration_ui.c b/src/signTxCVoteRegistration_ui.c index bebf957d..72b16aee 100644 --- a/src/signTxCVoteRegistration_ui.c +++ b/src/signTxCVoteRegistration_ui.c @@ -33,7 +33,7 @@ static void _displayVoteKey(ui_callback_fn_t callback) ); #elif defined(HAVE_NBGL) set_light_confirmation(true); - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + char encodedStr[BECH32_STRING_SIZE_MAX] = {0}; ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "cvote_vk", subctx->stateData.delegation.votePubKey, CVOTE_PUBLIC_KEY_LENGTH); fill_and_display_if_required("Vote public key", encodedStr, callback, respond_with_user_reject); #endif // HAVE_BAGL diff --git a/src/signTxOutput_ui.c b/src/signTxOutput_ui.c index 11e2287d..a682a632 100644 --- a/src/signTxOutput_ui.c +++ b/src/signTxOutput_ui.c @@ -124,7 +124,7 @@ void signTx_handleOutput_addressParams_ui_runStep() #ifdef HAVE_BAGL ui_displaySpendingInfoScreen(&subctx->stateData.destination.params, this_fn); #elif defined(HAVE_NBGL) -#define SPENDING_INFO_SIZE MAX(11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX, 2 * BECH32_BUFFER_SIZE_MAX) +#define SPENDING_INFO_SIZE MAX(BECH32_STRING_SIZE_MAX, BIP44_PATH_STRING_SIZE_MAX) char line1[30]; char spendingInfo[SPENDING_INFO_SIZE] = {0}; ui_getSpendingInfoScreen(line1, SIZEOF(line1), spendingInfo, SIZEOF(spendingInfo), &subctx->stateData.destination.params); @@ -327,7 +327,7 @@ void signTxOutput_handleDatumHash_ui_runStep() ); #elif defined(HAVE_NBGL) set_light_confirmation(true); - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + char encodedStr[BECH32_STRING_SIZE_MAX] = {0}; ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "datum", subctx->stateData.datumHash, OUTPUT_DATUM_HASH_LENGTH); fill_and_display_if_required("Datum hash", encodedStr, this_fn, respond_with_user_reject); #endif // HAVE_BAGL diff --git a/src/signTxPoolRegistration_ui.c b/src/signTxPoolRegistration_ui.c index 8c974e6f..971244d9 100644 --- a/src/signTxPoolRegistration_ui.c +++ b/src/signTxPoolRegistration_ui.c @@ -188,7 +188,7 @@ void handlePoolKey_ui_runStep() this_fn ); #elif defined(HAVE_NBGL) - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + char encodedStr[BECH32_STRING_SIZE_MAX] = {0}; ui_getBech32Screen( encodedStr, SIZEOF(encodedStr), "pool", @@ -229,7 +229,7 @@ void handlePoolVrfKey_ui_runStep() this_fn ); #elif defined(HAVE_NBGL) - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + char encodedStr[BECH32_STRING_SIZE_MAX] = {0}; ui_getBech32Screen( encodedStr, SIZEOF(encodedStr), "vrf_vk", diff --git a/src/signTx_ui.c b/src/signTx_ui.c index 00ef6930..5bf227e2 100644 --- a/src/signTx_ui.c +++ b/src/signTx_ui.c @@ -373,7 +373,7 @@ static inline void advanceCertificatesStateIfAppropriate() #ifdef HAVE_NBGL static void signTx_handleCertificate_ui_delegation_cb(void) { - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + char encodedStr[BECH32_STRING_SIZE_MAX] = {0}; ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "pool", BODY_CTX->stageData.certificate.poolKeyHash, SIZEOF(BODY_CTX->stageData.certificate.poolKeyHash)); fill_and_display_if_required("Pool", encodedStr, signTx_handleCertificate_ui_runStep, respond_with_user_reject); } @@ -463,7 +463,7 @@ void signTx_handleCertificate_ui_runStep() ); #elif defined(HAVE_NBGL) { - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + char encodedStr[BECH32_STRING_SIZE_MAX] = {0}; ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "stake_vkh", BODY_CTX->stageData.certificate.stakeCredential.keyHash, SIZEOF(BODY_CTX->stageData.certificate.stakeCredential.keyHash)); fill_and_display_if_required("Staking key hash", encodedStr, this_fn, respond_with_user_reject); } @@ -480,7 +480,7 @@ void signTx_handleCertificate_ui_runStep() ); #elif defined(HAVE_NBGL) { - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + char encodedStr[BECH32_STRING_SIZE_MAX] = {0}; ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "script", BODY_CTX->stageData.certificate.stakeCredential.scriptHash, SIZEOF(BODY_CTX->stageData.certificate.stakeCredential.scriptHash)); fill_and_display_if_required("Staking script hash", encodedStr, this_fn, respond_with_user_reject); } @@ -563,7 +563,7 @@ void signTx_handleCertificatePoolRetirement_ui_runStep() ); #elif defined(HAVE_NBGL) set_light_confirmation(true); - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + char encodedStr[BECH32_STRING_SIZE_MAX] = {0}; ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "pool", BODY_CTX->stageData.certificate.poolKeyHash, SIZEOF(BODY_CTX->stageData.certificate.poolKeyHash)); fill_and_display_if_required("Retire stake pool", encodedStr, this_fn, respond_with_user_reject); #endif // HAVE_BAGL @@ -731,7 +731,7 @@ void signTx_handleScriptDataHash_ui_runStep() this_fn ); #elif defined(HAVE_NBGL) - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + char encodedStr[BECH32_STRING_SIZE_MAX] = {0}; ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "script_data", BODY_CTX->stageData.scriptDataHash, SIZEOF(BODY_CTX->stageData.scriptDataHash)); fill_and_display_if_required("Script data hash", encodedStr, this_fn, respond_with_user_reject); #endif // HAVE_BAGL @@ -773,7 +773,7 @@ void signTx_handleRequiredSigner_ui_runStep() this_fn ); #elif defined(HAVE_NBGL) - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + char encodedStr[BECH32_STRING_SIZE_MAX] = {0}; ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "req_signer_vfk", BODY_CTX->stageData.requiredSigner.keyHash, SIZEOF(BODY_CTX->stageData.requiredSigner.keyHash)); fill_and_display_if_required("Required signer", encodedStr, this_fn, respond_with_user_reject); #endif // HAVE_BAGL diff --git a/src/uiScreens_bagl.c b/src/uiScreens_bagl.c index 284bb2eb..bdc8044f 100644 --- a/src/uiScreens_bagl.c +++ b/src/uiScreens_bagl.c @@ -56,7 +56,7 @@ void ui_displayBech32Screen( } // rough upper bound on required size is used - char encodedStr[11 + BECH32_PREFIX_LENGTH_MAX + 2 * BECH32_BUFFER_SIZE_MAX] = {0}; + char encodedStr[BECH32_STRING_SIZE_MAX] = {0}; explicit_bzero(encodedStr, SIZEOF(encodedStr)); { From bf5a0838f17d115ba1f86fad956dc187407393b8 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 14 Mar 2023 10:43:56 +0100 Subject: [PATCH 034/105] ui_nbgl: add callback to fill_address --- src/deriveAddress.c | 6 +++--- src/ui.h | 2 +- src/ui_nbgl.c | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/deriveAddress.c b/src/deriveAddress.c index ff224230..6354b9b0 100644 --- a/src/deriveAddress.c +++ b/src/deriveAddress.c @@ -202,7 +202,7 @@ static void _displaySpendingInfo_displayAddr(ui_callback_fn_t* this_fn) char line1[30] = {0}; char spendingInfo[SPENDING_INFO_SIZE] = {0}; ui_getSpendingInfoScreen(line1, SIZEOF(line1), spendingInfo, SIZEOF(spendingInfo), &ctx->addressParams); - fill_address_data(line1, spendingInfo); + fill_address_data(line1, spendingInfo, this_fn); #endif // HAVE_BAGL } @@ -214,7 +214,7 @@ static void _displayStakingInfo_displayAddr(ui_callback_fn_t* this_fn) char line1[30] = {0}; char stakingInfo[120] = {0}; ui_getStakingInfoScreen(line1, SIZEOF(line1), stakingInfo, SIZEOF(stakingInfo), &ctx->addressParams); - fill_address_data(line1, stakingInfo); + fill_address_data(line1, stakingInfo, this_fn); #endif // HAVE_BAGL } @@ -235,7 +235,7 @@ static void _displayAddress(ui_callback_fn_t* this_fn) ctx->address.buffer, ctx->address.size ); - fill_address_data((char*)"Address", humanAddress); + fill_address_data((char*)"Address", humanAddress, this_fn); #endif // HAVE_BAGL } diff --git a/src/ui.h b/src/ui.h index 46b16bd2..aeed5d2f 100644 --- a/src/ui.h +++ b/src/ui.h @@ -9,7 +9,7 @@ typedef void (*callback_t)(void); void set_light_confirmation(bool needed); void display_address(callback_t user_accept_cb, callback_t user_reject_cb); -void fill_address_data(char* text, char* content); +void fill_address_data(char* text, char* content, callback_t callback); void fill_and_display_if_required(const char* line1, const char* line2, callback_t user_accept_cb, callback_t user_reject_cb); void fill_and_display_new_page(const char* line1, const char* line2, callback_t user_accept_cb, callback_t user_reject_cb); void force_display(callback_t user_accept_cb, callback_t user_reject_cb); diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index 777d8af9..aa25e4b7 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -453,8 +453,9 @@ void fill_and_display_new_page(const char *line1, const char *line2, } } -void fill_address_data(char *text, char *content) { +void fill_address_data(char *text, char *content, callback_t callback) { fill_current_element(text, content); + trigger_callback(callback); } void display_confirmation(const char *text1, const char *text2, From afc5d090bb12dfd50c7e4e1f68d7b2c033b2cf9e Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 14 Mar 2023 15:51:57 +0100 Subject: [PATCH 035/105] deriveNativeScriptHash_ui: fix script display --- src/deriveNativeScriptHash_ui.c | 13 +++++-------- src/deriveNativeScriptHash_ui.h | 1 - src/ui.h | 1 - src/ui_nbgl.c | 24 ------------------------ 4 files changed, 5 insertions(+), 34 deletions(-) diff --git a/src/deriveNativeScriptHash_ui.c b/src/deriveNativeScriptHash_ui.c index 627a8b4b..62296e61 100644 --- a/src/deriveNativeScriptHash_ui.c +++ b/src/deriveNativeScriptHash_ui.c @@ -77,7 +77,7 @@ static void deriveScriptHash_display_ui_position(uint8_t level, ui_callback_fn_t ); #elif defined(HAVE_NBGL) set_light_confirmation(true); - fill_and_display_new_page(HEADER, positionDescription, callback, respond_with_user_reject); + display_prompt("Review Script", positionDescription, callback, respond_with_user_reject); #endif // HAVE_BAGL } @@ -107,20 +107,17 @@ void deriveScriptHash_display_ui_runStep() uint8_t level = _getScriptLevelForPosition(); if (level == 0) { TRACE("Skip showing position"); + #ifdef HAVE_BAGL UI_STEP_JUMP(DISPLAY_UI_STEP_SCRIPT_CONTENT); + #elif defined(HAVE_NBGL) + display_prompt("Review Script", "", this_fn, respond_with_user_reject); + #endif // HAVE_NBGL } else { deriveScriptHash_display_ui_position(level, this_fn); } } - UI_STEP(DISPLAY_UI_STEP_TITLE) { - #ifdef HAVE_BAGL - UI_STEP_JUMP(DISPLAY_UI_STEP_SCRIPT_CONTENT); - #elif defined(HAVE_NBGL) - display_prompt("Review Script", "", this_fn, respond_with_user_reject); - #endif // HAVE_NBGL - } #ifdef HAVE_NBGL UI_STEP(DISPLAY_UI_STEP_SCRIPT_TYPE) { set_light_confirmation(true); diff --git a/src/deriveNativeScriptHash_ui.h b/src/deriveNativeScriptHash_ui.h index 1495748c..95460806 100644 --- a/src/deriveNativeScriptHash_ui.h +++ b/src/deriveNativeScriptHash_ui.h @@ -2,7 +2,6 @@ #define H_CARDANO_APP_DERIVE_NATIVE_SCRIPT_HASH_UI enum { DISPLAY_UI_STEP_POSITION = 200, - DISPLAY_UI_STEP_TITLE, #ifdef HAVE_NBGL DISPLAY_UI_STEP_SCRIPT_TYPE, #endif // HAVE_NBGL diff --git a/src/ui.h b/src/ui.h index aeed5d2f..1d3eabbe 100644 --- a/src/ui.h +++ b/src/ui.h @@ -11,7 +11,6 @@ void set_light_confirmation(bool needed); void display_address(callback_t user_accept_cb, callback_t user_reject_cb); void fill_address_data(char* text, char* content, callback_t callback); void fill_and_display_if_required(const char* line1, const char* line2, callback_t user_accept_cb, callback_t user_reject_cb); -void fill_and_display_new_page(const char* line1, const char* line2, callback_t user_accept_cb, callback_t user_reject_cb); void force_display(callback_t user_accept_cb, callback_t user_reject_cb); void display_confirmation(const char* text1, const char* text2, const char* confirmText, const char* rejectText, callback_t user_accept_cb, callback_t user_reject_cb); void display_page(callback_t user_accept_cb, callback_t user_reject_cb); diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index aa25e4b7..bc835fb8 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -429,30 +429,6 @@ void fill_and_display_if_required(const char *line1, const char *line2, } } -void fill_and_display_new_page(const char *line1, const char *line2, - callback_t userAcceptCallback, - callback_t userRejectCallback) { - - ASSERT(strlen(line1) <= MAX_TAG_TITLE_LINE_LENGTH); - ASSERT(strlen(line2) <= MAX_TAG_CONTENT_LENGTH); - - if (uiContext.pendingElement) { - handle_pending_element(); - } - - if (uiContext.currentLineCount > 0) { - TRACE("Display page and add pending element"); - fill_pending_element(line1, line2); - - display_page(userAcceptCallback, userRejectCallback); - } else { - TRACE("Add element to page"); - fill_current_element(line1, line2); - uiContext.currentLineCount += get_element_line_count(line2); - display_continue(userAcceptCallback); - } -} - void fill_address_data(char *text, char *content, callback_t callback) { fill_current_element(text, content); trigger_callback(callback); From 382f6073d8ad12e88289289648897d7e2dd17c75 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 14 Mar 2023 16:58:46 +0100 Subject: [PATCH 036/105] Makefile: remove deprecated flags --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index 68c4b749..e8ca98e3 100644 --- a/Makefile +++ b/Makefile @@ -86,7 +86,6 @@ DEFINES += HAVE_BOLOS_APP_STACK_CANARY ifeq ($(TARGET_NAME),TARGET_NANOS) DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=128 -DEFINES += HAVE_BOLOS_UX HAVE_UX_LEGACY COMPLIANCE_UX_160 else DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=300 DEFINES += HAVE_GLO096 From ebace8102a00fd9311a8f6d6587f88665083090e Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 27 Mar 2023 11:05:07 +0200 Subject: [PATCH 037/105] Apply linting --- src/deriveNativeScriptHash_ui.c | 3 +- src/io.c | 4 +- src/signTxPoolRegistration_ui.c | 2 +- src/ui_menu_nbgl.c | 101 ++-- src/ui_nbgl.c | 865 +++++++++++++++++--------------- 5 files changed, 509 insertions(+), 466 deletions(-) diff --git a/src/deriveNativeScriptHash_ui.c b/src/deriveNativeScriptHash_ui.c index 62296e61..32c0c055 100644 --- a/src/deriveNativeScriptHash_ui.c +++ b/src/deriveNativeScriptHash_ui.c @@ -112,8 +112,7 @@ void deriveScriptHash_display_ui_runStep() #elif defined(HAVE_NBGL) display_prompt("Review Script", "", this_fn, respond_with_user_reject); #endif // HAVE_NBGL - } - else { + } else { deriveScriptHash_display_ui_position(level, this_fn); } } diff --git a/src/io.c b/src/io.c index b78d7ba4..93fab304 100644 --- a/src/io.c +++ b/src/io.c @@ -106,11 +106,11 @@ unsigned char io_event(unsigned char channel MARK_UNUSED) UX_DEFAULT_EVENT(); #endif break; -#ifdef HAVE_NBGL + #ifdef HAVE_NBGL case SEPROXYHAL_TAG_FINGER_EVENT: UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); break; -#endif // HAVE_NBGL + #endif // HAVE_NBGL case SEPROXYHAL_TAG_TICKER_EVENT: UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, { diff --git a/src/signTxPoolRegistration_ui.c b/src/signTxPoolRegistration_ui.c index 971244d9..283c0d5b 100644 --- a/src/signTxPoolRegistration_ui.c +++ b/src/signTxPoolRegistration_ui.c @@ -338,7 +338,7 @@ void handlePoolFinancials_ui_runStep() #ifdef HAVE_NBGL static void handlePoolRewardAccount_ui_runStep_cb(void) { - force_display(handlePoolRewardAccount_ui_runStep, respond_with_user_reject); + force_display(handlePoolRewardAccount_ui_runStep, respond_with_user_reject); } #endif diff --git a/src/ui_menu_nbgl.c b/src/ui_menu_nbgl.c index ae75c9b3..98cc9a14 100644 --- a/src/ui_menu_nbgl.c +++ b/src/ui_menu_nbgl.c @@ -30,69 +30,78 @@ #define NB_SETTINGS_SWITCHES 1 enum { - SWITCH_APP_MODE_TOKEN = FIRST_USER_TOKEN, + SWITCH_APP_MODE_TOKEN = FIRST_USER_TOKEN, }; static nbgl_layoutSwitch_t switches[NB_SETTINGS_SWITCHES]; -static const char *const infoTypes[] = {"Version", "Developer", "Copyright"}; -static const char *const infoContents[] = {APPVERSION, "Vacuumlabs", - "(c) 2022 Ledger"}; +static const char* const infoTypes[] = {"Version", "Developer", "Copyright"}; +static const char* const infoContents[] = {APPVERSION, "Vacuumlabs", + "(c) 2022 Ledger" + }; static const int INS_NONE = -1; // Settings -static void exit(void) { os_sched_exit(-1); } +static void exit(void) +{ + os_sched_exit(-1); +} -static bool settings_navigation_callback(uint8_t page, nbgl_pageContent_t *content) { - if (page == 0) { - switches[0].text = (char *)"Enable expert mode"; - switches[0].subText = (char *)"Select application mode"; - switches[0].token = SWITCH_APP_MODE_TOKEN; - switches[0].tuneId = TUNE_TAP_CASUAL; - switches[0].initState = app_mode_expert(); +static bool settings_navigation_callback(uint8_t page, nbgl_pageContent_t* content) +{ + if (page == 0) { + switches[0].text = (char*)"Enable expert mode"; + switches[0].subText = (char*)"Select application mode"; + switches[0].token = SWITCH_APP_MODE_TOKEN; + switches[0].tuneId = TUNE_TAP_CASUAL; + switches[0].initState = app_mode_expert(); - content->type = SWITCHES_LIST; - content->switchesList.nbSwitches = NB_SETTINGS_SWITCHES; - content->switchesList.switches = (nbgl_layoutSwitch_t *)switches; - } else if (page == 1) { - content->type = INFOS_LIST; - content->infosList.nbInfos = NB_INFO_FIELDS; - content->infosList.infoTypes = (const char **)infoTypes; - content->infosList.infoContents = (const char **)infoContents; - } else { - return false; - } - return true; + content->type = SWITCHES_LIST; + content->switchesList.nbSwitches = NB_SETTINGS_SWITCHES; + content->switchesList.switches = (nbgl_layoutSwitch_t*)switches; + } else if (page == 1) { + content->type = INFOS_LIST; + content->infosList.nbInfos = NB_INFO_FIELDS; + content->infosList.infoTypes = (const char**)infoTypes; + content->infosList.infoContents = (const char**)infoContents; + } else { + return false; + } + return true; } -static void settings_control_callback(int token, uint8_t index) { - UNUSED(index); - switch (token) { - case SWITCH_APP_MODE_TOKEN: - app_mode_set_expert(index); - break; +static void settings_control_callback(int token, uint8_t index) +{ + UNUSED(index); + switch (token) { + case SWITCH_APP_MODE_TOKEN: + app_mode_set_expert(index); + break; - default: - PRINTF("Should not happen !"); - break; - } + default: + PRINTF("Should not happen !"); + break; + } } -static void ui_menu_settings(void) { - nbgl_useCaseSettings((char *)"Cardano settings", PAGE_START, NB_PAGE_SETTING, - IS_TOUCHABLE, ui_idle_flow, settings_navigation_callback, - settings_control_callback); +static void ui_menu_settings(void) +{ + nbgl_useCaseSettings((char*)"Cardano settings", PAGE_START, NB_PAGE_SETTING, + IS_TOUCHABLE, ui_idle_flow, settings_navigation_callback, + settings_control_callback); } -void ui_idle_flow(void) { - TRACE("RESETTING\n\n"); - // We need to make sure the ui context is reset even if the app restarts - nbgl_reset_transaction_full_context(); - nbgl_useCaseHome((char *)"Cardano", &C_cardano_64, NULL, true, - ui_menu_settings, exit); +void ui_idle_flow(void) +{ + TRACE("RESETTING\n\n"); + // We need to make sure the ui context is reset even if the app restarts + nbgl_reset_transaction_full_context(); + nbgl_useCaseHome((char*)"Cardano", &C_cardano_64, NULL, true, + ui_menu_settings, exit); } -void ui_idle(void) { - currentInstruction = INS_NONE; +void ui_idle(void) +{ + currentInstruction = INS_NONE; } #endif // HAVE_NBGL diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index bc835fb8..606eb3db 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -29,36 +29,36 @@ #define MAX_TEXT_STRING 50 #define PENDING_ELEMENT_INDEX MAX_TAG_PER_PAGE_COUNT enum { - CANCEL_PROMPT_TOKEN = 1, - ACCEPT_PAGE_TOKEN, - CONFIRMATION_STATUS_TOKEN, + CANCEL_PROMPT_TOKEN = 1, + ACCEPT_PAGE_TOKEN, + CONFIRMATION_STATUS_TOKEN, }; typedef struct { - char *confirmedStatus; // text displayed in confirmation page (after long press) - char *rejectedStatus; // text displayed in rejection page (after reject confirmed) - callback_t approvedCallback; - callback_t rejectedCallback; - callback_t pendingDisplayPageFn; - bool pendingElement; - uint8_t currentLineCount; - uint8_t currentElementCount; - char tagTitle[MAX_TAG_PER_PAGE_COUNT + 1][MAX_TAG_TITLE_LINE_LENGTH]; - char tagContent[MAX_TAG_PER_PAGE_COUNT + 1][MAX_TAG_CONTENT_LENGTH]; - char pageText[2][MAX_TEXT_STRING]; - bool lightConfirmation; - nbgl_layoutTagValueList_t pairList; + char* confirmedStatus; // text displayed in confirmation page (after long press) + char* rejectedStatus; // text displayed in rejection page (after reject confirmed) + callback_t approvedCallback; + callback_t rejectedCallback; + callback_t pendingDisplayPageFn; + bool pendingElement; + uint8_t currentLineCount; + uint8_t currentElementCount; + char tagTitle[MAX_TAG_PER_PAGE_COUNT + 1][MAX_TAG_TITLE_LINE_LENGTH]; + char tagContent[MAX_TAG_PER_PAGE_COUNT + 1][MAX_TAG_CONTENT_LENGTH]; + char pageText[2][MAX_TEXT_STRING]; + bool lightConfirmation; + nbgl_layoutTagValueList_t pairList; } UiContext_t; -static nbgl_page_t *pageContext; +static nbgl_page_t* pageContext; static nbgl_layoutTagValue_t tagValues[5]; static UiContext_t uiContext = { - .rejectedStatus = NULL, - .confirmedStatus = NULL, - .currentLineCount = 0, - .currentElementCount = 0, - .pendingElement = false, - .lightConfirmation = 0, + .rejectedStatus = NULL, + .confirmedStatus = NULL, + .currentLineCount = 0, + .currentElementCount = 0, + .pendingElement = false, + .lightConfirmation = 0, }; // Forward declaration @@ -67,433 +67,468 @@ static void display_confirmation_status(void); static void display_cancel_status(void); static void trigger_callback(callback_t userAcceptCallback); -static void release_context(void) { - if (pageContext != NULL) { - nbgl_pageRelease(pageContext); - pageContext = NULL; - } -} - -static inline uint8_t get_element_line_count(const char *line) { - return strlen(line) / MAX_TAG_CONTENT_CHAR_PER_LINE + 2; -} - -static void set_callbacks(callback_t approvedCallback, callback_t rejectedCallback){ - uiContext.approvedCallback = approvedCallback; - uiContext.rejectedCallback = rejectedCallback; -} - -static void fill_current_element(const char* text, const char* content) { - strncpy(uiContext.tagTitle[uiContext.currentElementCount], text, MAX_TAG_TITLE_LINE_LENGTH); - strncpy(uiContext.tagContent[uiContext.currentElementCount], content, MAX_TAG_CONTENT_LENGTH); - - uiContext.currentElementCount++; - uiContext.currentLineCount += get_element_line_count(content); -} - -static void fill_pending_element(const char* text, const char* content) { - strncpy(uiContext.tagTitle[PENDING_ELEMENT_INDEX], text, MAX_TAG_TITLE_LINE_LENGTH); - strncpy(uiContext.tagContent[PENDING_ELEMENT_INDEX], content, MAX_TAG_CONTENT_LENGTH); - - uiContext.pendingElement = true; -} - -static void reset_transaction_current_context(void) { - uiContext.currentElementCount = 0; - uiContext.currentLineCount = 0; -} - -void nbgl_reset_transaction_full_context(void) { - reset_transaction_current_context(); - uiContext.pendingElement = 0; - uiContext.lightConfirmation = false; - uiContext.rejectedStatus = NULL; - uiContext.confirmedStatus = NULL; - uiContext.approvedCallback = NULL; - uiContext.rejectedCallback = NULL; - uiContext.pendingDisplayPageFn = NULL; -} - -void set_light_confirmation(bool needed) { - uiContext.lightConfirmation = needed; -} - -static void display_callback(int token, unsigned char index) { - (void)index; - callback_t callback; - - release_context(); - - switch (token) { - case CANCEL_PROMPT_TOKEN: - display_cancel(); - break; - case ACCEPT_PAGE_TOKEN: - if (uiContext.pendingDisplayPageFn) { - // Hook the approve callback so that the pending page is displayed - // Once this page is approved, the approve callback will be called - callback = uiContext.pendingDisplayPageFn; - uiContext.pendingDisplayPageFn = NULL; - } else { - callback = uiContext.approvedCallback; - } - callback(); - break; - case CONFIRMATION_STATUS_TOKEN: - display_confirmation_status(); - break; - default: - TRACE("%d unknown", token); - } -} - -static void _display_confirmation(void) { - TRACE("_confirmation"); - - release_context(); - - nbgl_pageNavigationInfo_t info = { - .activePage = 0, - .nbPages = 0, - .navType = NAV_WITH_TAP, - .progressIndicator = true, - .navWithTap.backButton = false, - .navWithTap.nextPageText = NULL, - .navWithTap.quitText = "Reject", - .quitToken = CANCEL_PROMPT_TOKEN, - .tuneId = TUNE_TAP_CASUAL}; - - nbgl_pageContent_t content = { - .type = INFO_LONG_PRESS, - .infoLongPress.icon = &C_cardano_64, - .infoLongPress.text = uiContext.pageText[0], - .infoLongPress.longPressText = (char *)"Hold to approve", - .infoLongPress.longPressToken = CONFIRMATION_STATUS_TOKEN, - .infoLongPress.tuneId = TUNE_TAP_NEXT}; - - pageContext = nbgl_pageDrawGenericContent(&display_callback, &info, &content); - -#ifdef HEADLESS - nbgl_refresh(); - trigger_callback(uiContext.approvedCallback); -#endif -} - -static void light_confirm_callback(bool confirm) { - if (confirm) { - display_confirmation_status(); - } else { - display_cancel_status(); - } -} - -static void _display_light_confirmation(void) { - TRACE("_light_confirmation"); - - nbgl_useCaseChoice(&C_cardano_64, uiContext.pageText[0], (char *)"", - (char *)"Confirm", (char *)"Cancel", light_confirm_callback); +static void release_context(void) +{ + if (pageContext != NULL) { + nbgl_pageRelease(pageContext); + pageContext = NULL; + } +} + +static inline uint8_t get_element_line_count(const char* line) +{ + return strlen(line) / MAX_TAG_CONTENT_CHAR_PER_LINE + 2; +} + +static void set_callbacks(callback_t approvedCallback, callback_t rejectedCallback) +{ + uiContext.approvedCallback = approvedCallback; + uiContext.rejectedCallback = rejectedCallback; +} + +static void fill_current_element(const char* text, const char* content) +{ + strncpy(uiContext.tagTitle[uiContext.currentElementCount], text, MAX_TAG_TITLE_LINE_LENGTH); + strncpy(uiContext.tagContent[uiContext.currentElementCount], content, MAX_TAG_CONTENT_LENGTH); + + uiContext.currentElementCount++; + uiContext.currentLineCount += get_element_line_count(content); +} + +static void fill_pending_element(const char* text, const char* content) +{ + strncpy(uiContext.tagTitle[PENDING_ELEMENT_INDEX], text, MAX_TAG_TITLE_LINE_LENGTH); + strncpy(uiContext.tagContent[PENDING_ELEMENT_INDEX], content, MAX_TAG_CONTENT_LENGTH); + + uiContext.pendingElement = true; +} + +static void reset_transaction_current_context(void) +{ + uiContext.currentElementCount = 0; + uiContext.currentLineCount = 0; +} + +void nbgl_reset_transaction_full_context(void) +{ + reset_transaction_current_context(); + uiContext.pendingElement = 0; + uiContext.lightConfirmation = false; + uiContext.rejectedStatus = NULL; + uiContext.confirmedStatus = NULL; + uiContext.approvedCallback = NULL; + uiContext.rejectedCallback = NULL; + uiContext.pendingDisplayPageFn = NULL; +} + +void set_light_confirmation(bool needed) +{ + uiContext.lightConfirmation = needed; +} + +static void display_callback(int token, unsigned char index) +{ + (void)index; + callback_t callback; + + release_context(); + + switch (token) { + case CANCEL_PROMPT_TOKEN: + display_cancel(); + break; + case ACCEPT_PAGE_TOKEN: + if (uiContext.pendingDisplayPageFn) { + // Hook the approve callback so that the pending page is displayed + // Once this page is approved, the approve callback will be called + callback = uiContext.pendingDisplayPageFn; + uiContext.pendingDisplayPageFn = NULL; + } else { + callback = uiContext.approvedCallback; + } + callback(); + break; + case CONFIRMATION_STATUS_TOKEN: + display_confirmation_status(); + break; + default: + TRACE("%d unknown", token); + } +} + +static void _display_confirmation(void) +{ + TRACE("_confirmation"); + + release_context(); + + nbgl_pageNavigationInfo_t info = { + .activePage = 0, + .nbPages = 0, + .navType = NAV_WITH_TAP, + .progressIndicator = true, + .navWithTap.backButton = false, + .navWithTap.nextPageText = NULL, + .navWithTap.quitText = "Reject", + .quitToken = CANCEL_PROMPT_TOKEN, + .tuneId = TUNE_TAP_CASUAL + }; + + nbgl_pageContent_t content = { + .type = INFO_LONG_PRESS, + .infoLongPress.icon = &C_cardano_64, + .infoLongPress.text = uiContext.pageText[0], + .infoLongPress.longPressText = (char*)"Hold to approve", + .infoLongPress.longPressToken = CONFIRMATION_STATUS_TOKEN, + .infoLongPress.tuneId = TUNE_TAP_NEXT + }; + + pageContext = nbgl_pageDrawGenericContent(&display_callback, &info, &content); + + #ifdef HEADLESS + nbgl_refresh(); + trigger_callback(uiContext.approvedCallback); + #endif +} + +static void light_confirm_callback(bool confirm) +{ + if (confirm) { + display_confirmation_status(); + } else { + display_cancel_status(); + } +} + +static void _display_light_confirmation(void) +{ + TRACE("_light_confirmation"); + + nbgl_useCaseChoice(&C_cardano_64, uiContext.pageText[0], (char*)"", + (char*)"Confirm", (char*)"Cancel", light_confirm_callback); + + #ifdef HEADLESS + trigger_callback(uiContext.approvedCallback); + #endif +} + +static void display_cancel(void) +{ + if (uiContext.lightConfirmation) { + display_cancel_status(); + } else { + nbgl_useCaseConfirm((char*)"Reject ?", NULL, (char*)"Yes, Reject", + (char*)"Go back", display_cancel_status); + } +} + +static void cancellation_status_callback(void) +{ + if (uiContext.rejectedCallback) { + uiContext.rejectedCallback(); + } + ui_idle_flow(); +} + +static void display_cancel_status(void) +{ + ui_idle(); + + if (uiContext.rejectedStatus) { + nbgl_useCaseStatus(uiContext.rejectedStatus, false, cancellation_status_callback); + } else { + nbgl_useCaseStatus((char*)"Action rejected", false, cancellation_status_callback); + } +} + +static void _display_page(void) +{ + TRACE("_page"); + + release_context(); + + for (uint8_t i = 0; i < uiContext.currentElementCount; i++) { + tagValues[i].item = uiContext.tagTitle[i]; + tagValues[i].value = uiContext.tagContent[i]; + } + + nbgl_pageNavigationInfo_t info = { + .activePage = 0, + .nbPages = 0, + .navType = NAV_WITH_TAP, + .progressIndicator = true, + .navWithTap.backButton = false, + .navWithTap.nextPageText = (char*)"Tap to continue", + .navWithTap.nextPageToken = ACCEPT_PAGE_TOKEN, + .navWithTap.quitText = (char*)"Cancel", + .quitToken = CANCEL_PROMPT_TOKEN, + .tuneId = TUNE_TAP_CASUAL + }; + + nbgl_pageContent_t content = { + .type = TAG_VALUE_LIST, + .tagValueList.nbPairs = uiContext.currentElementCount, + .tagValueList.pairs = (nbgl_layoutTagValue_t*)tagValues + }; + + pageContext = nbgl_pageDrawGenericContent(&display_callback, &info, &content); + reset_transaction_current_context(); + + #ifdef HEADLESS + nbgl_refresh(); + trigger_callback(uiContext.approvedCallback); + #endif +} + +static void _display_prompt(void) +{ + TRACE("_prompt"); + + nbgl_useCaseReviewStart(&C_cardano_64, uiContext.pageText[0], + uiContext.pageText[1], (char*)"Reject if not sure", + uiContext.approvedCallback, &display_cancel); + #ifdef HEADLESS + nbgl_refresh(); + trigger_callback(uiContext.approvedCallback); + #endif +} + +static void _display_warning(void) +{ + TRACE("_warning"); -#ifdef HEADLESS - trigger_callback(uiContext.approvedCallback); -#endif -} - -static void display_cancel(void) { - if (uiContext.lightConfirmation) { - display_cancel_status(); - } else { - nbgl_useCaseConfirm((char *)"Reject ?", NULL, (char *)"Yes, Reject", - (char *)"Go back", display_cancel_status); - } -} - -static void cancellation_status_callback(void) { - if (uiContext.rejectedCallback) { - uiContext.rejectedCallback(); - } - ui_idle_flow(); -} - -static void display_cancel_status(void) { - ui_idle(); - - if (uiContext.rejectedStatus) { - nbgl_useCaseStatus(uiContext.rejectedStatus, false, cancellation_status_callback); - } else { - nbgl_useCaseStatus((char *)"Action rejected", false, cancellation_status_callback); - } -} - -static void _display_page(void) { - TRACE("_page"); - - release_context(); - - for (uint8_t i = 0; i < uiContext.currentElementCount; i++) { - tagValues[i].item = uiContext.tagTitle[i]; - tagValues[i].value = uiContext.tagContent[i]; - } - - nbgl_pageNavigationInfo_t info = { - .activePage = 0, - .nbPages = 0, - .navType = NAV_WITH_TAP, - .progressIndicator = true, - .navWithTap.backButton = false, - .navWithTap.nextPageText = (char *)"Tap to continue", - .navWithTap.nextPageToken = ACCEPT_PAGE_TOKEN, - .navWithTap.quitText = (char *)"Cancel", - .quitToken = CANCEL_PROMPT_TOKEN, - .tuneId = TUNE_TAP_CASUAL}; - - nbgl_pageContent_t content = { - .type = TAG_VALUE_LIST, - .tagValueList.nbPairs = uiContext.currentElementCount, - .tagValueList.pairs = (nbgl_layoutTagValue_t *)tagValues}; - - pageContext = nbgl_pageDrawGenericContent(&display_callback, &info, &content); - reset_transaction_current_context(); - -#ifdef HEADLESS - nbgl_refresh(); - trigger_callback(uiContext.approvedCallback); -#endif -} - -static void _display_prompt(void) { - TRACE("_prompt"); - - nbgl_useCaseReviewStart(&C_cardano_64, uiContext.pageText[0], - uiContext.pageText[1], (char *)"Reject if not sure", - uiContext.approvedCallback, &display_cancel); -#ifdef HEADLESS - nbgl_refresh(); - trigger_callback(uiContext.approvedCallback); -#endif -} - -static void _display_warning(void) { - TRACE("_warning"); - - nbgl_useCaseReviewStart(&C_warning64px, (char *)"WARNING", - uiContext.pageText[0], (char *)"Reject if not sure", - uiContext.approvedCallback, &display_cancel); -#ifdef HEADLESS - nbgl_refresh(); - trigger_callback(uiContext.approvedCallback); -#endif -} - -static void confirmation_status_callback(void) { - if (uiContext.confirmedStatus) { - nbgl_useCaseStatus(uiContext.confirmedStatus, true, ui_idle_flow); - } else { - nbgl_useCaseStatus((char *)"ACTION\nCONFIRMED", true, ui_idle_flow); - } - -} - -static void display_confirmation_status(void) { - if (uiContext.approvedCallback) { - uiContext.approvedCallback(); - } - - trigger_callback(&confirmation_status_callback); -} + nbgl_useCaseReviewStart(&C_warning64px, (char*)"WARNING", + uiContext.pageText[0], (char*)"Reject if not sure", + uiContext.approvedCallback, &display_cancel); + #ifdef HEADLESS + nbgl_refresh(); + trigger_callback(uiContext.approvedCallback); + #endif +} + +static void confirmation_status_callback(void) +{ + if (uiContext.confirmedStatus) { + nbgl_useCaseStatus(uiContext.confirmedStatus, true, ui_idle_flow); + } else { + nbgl_useCaseStatus((char*)"ACTION\nCONFIRMED", true, ui_idle_flow); + } + +} + +static void display_confirmation_status(void) +{ + if (uiContext.approvedCallback) { + uiContext.approvedCallback(); + } + + trigger_callback(&confirmation_status_callback); +} + +static void display_address_callback(void) +{ + uint8_t address_index = 0; + + // Address field is not displayed in pairList, so there is one element less. + uiContext.pairList.nbPairs = uiContext.currentElementCount - 1; + uiContext.pairList.pairs = tagValues; + + uiContext.confirmedStatus = (char*)"ADDRESS\nVERIFIED"; + uiContext.rejectedStatus = (char*)"Address rejected"; + + for (uint8_t i = 0; i < uiContext.currentElementCount; i++) { + if (strcmp(uiContext.tagTitle[i], "Address")) { + tagValues[i].item = uiContext.tagTitle[i]; + tagValues[i].value = uiContext.tagContent[i]; + } else { + address_index = i; + } + } + + nbgl_useCaseAddressConfirmationExt(uiContext.tagContent[address_index], light_confirm_callback, &uiContext.pairList); + reset_transaction_current_context(); + + #ifdef HEADLESS + nbgl_refresh(); + trigger_callback(&display_confirmation_status); + #endif +} + +static void trigger_callback(callback_t userAcceptCallback) +{ + // Hack to trigger a callback from NBGL while leaving the screen untouched + nbgl_layoutDescription_t layoutDescription; + nbgl_layout_t* layout = NULL; + nbgl_layoutCenteredInfo_t centeredInfo = { + .text1 = NULL, + .text2 = NULL, + .text3 = NULL, + .style = 0, + .icon = NULL, + .offsetY = 0 + }; + + release_context(); -static void display_address_callback(void) { - uint8_t address_index = 0; + layoutDescription.modal = false; + layoutDescription.withLeftBorder = true; + + layoutDescription.onActionCallback = NULL; + layoutDescription.tapActionText = (char*)""; + layoutDescription.tapActionToken = 0; + layoutDescription.tapTuneId = TUNE_TAP_CASUAL; - // Address field is not displayed in pairList, so there is one element less. - uiContext.pairList.nbPairs = uiContext.currentElementCount - 1; - uiContext.pairList.pairs = tagValues; - - uiContext.confirmedStatus = (char *)"ADDRESS\nVERIFIED"; - uiContext.rejectedStatus = (char *)"Address rejected"; - - for (uint8_t i = 0; i < uiContext.currentElementCount; i++) { - if (strcmp(uiContext.tagTitle[i], "Address")) { - tagValues[i].item = uiContext.tagTitle[i]; - tagValues[i].value = uiContext.tagContent[i]; - } - else { - address_index = i; - } - } - - nbgl_useCaseAddressConfirmationExt(uiContext.tagContent[address_index], light_confirm_callback, &uiContext.pairList); - reset_transaction_current_context(); - -#ifdef HEADLESS - nbgl_refresh(); - trigger_callback(&display_confirmation_status); -#endif -} - -static void trigger_callback(callback_t userAcceptCallback) { - // Hack to trigger a callback from NBGL while leaving the screen untouched - nbgl_layoutDescription_t layoutDescription; - nbgl_layout_t *layout = NULL; - nbgl_layoutCenteredInfo_t centeredInfo = { - .text1 = NULL, - .text2 = NULL, - .text3 = NULL, - .style = 0, - .icon = NULL, - .offsetY = 0 - }; - - release_context(); - - layoutDescription.modal = false; - layoutDescription.withLeftBorder = true; - - layoutDescription.onActionCallback = NULL; - layoutDescription.tapActionText = (char *)""; - layoutDescription.tapActionToken = 0; - layoutDescription.tapTuneId = TUNE_TAP_CASUAL; - - layoutDescription.ticker.tickerCallback = userAcceptCallback; - layoutDescription.ticker.tickerIntervale = 0; - layoutDescription.ticker.tickerValue = 100; - pageContext = nbgl_layoutGet(&layoutDescription); - - nbgl_layoutAddCenteredInfo(layout, ¢eredInfo); -} - -static void handle_pending_element(void) { - TRACE("Add pending element"); - ASSERT(uiContext.currentElementCount == 0); - ASSERT(uiContext.currentLineCount == 0); - - fill_current_element(uiContext.tagTitle[PENDING_ELEMENT_INDEX], uiContext.tagContent[PENDING_ELEMENT_INDEX]); - - uiContext.pendingElement = false; -} + layoutDescription.ticker.tickerCallback = userAcceptCallback; + layoutDescription.ticker.tickerIntervale = 0; + layoutDescription.ticker.tickerValue = 100; + pageContext = nbgl_layoutGet(&layoutDescription); + + nbgl_layoutAddCenteredInfo(layout, ¢eredInfo); +} + +static void handle_pending_element(void) +{ + TRACE("Add pending element"); + ASSERT(uiContext.currentElementCount == 0); + ASSERT(uiContext.currentLineCount == 0); -static void _display_page_or_call_function(callback_t displayPageFn) { - if (uiContext.pendingElement) { - handle_pending_element(); - } + fill_current_element(uiContext.tagTitle[PENDING_ELEMENT_INDEX], uiContext.tagContent[PENDING_ELEMENT_INDEX]); + + uiContext.pendingElement = false; +} + +static void _display_page_or_call_function(callback_t displayPageFn) +{ + if (uiContext.pendingElement) { + handle_pending_element(); + } - if (uiContext.currentElementCount > 0) { - // We were request to display a page using displayPageFn and then call - // specific callbacks. However we have pending elements to display first. - // Therefore, temporally save displayPageFn in pendingDisplayPageFn and - // display these pending elements. - // Once these pending elements page is approved, the generic display_callback() - // function will be called, and it will then execute the function stored - // in pendingDisplayPageFn instead of the approvedCallback. - // therefore our screen will be displayed, and if it is approved, at this moment - // the approvedCallback will be called. - uiContext.pendingDisplayPageFn = displayPageFn; - _display_page(); - } else { - displayPageFn(); - } + if (uiContext.currentElementCount > 0) { + // We were request to display a page using displayPageFn and then call + // specific callbacks. However we have pending elements to display first. + // Therefore, temporally save displayPageFn in pendingDisplayPageFn and + // display these pending elements. + // Once these pending elements page is approved, the generic display_callback() + // function will be called, and it will then execute the function stored + // in pendingDisplayPageFn instead of the approvedCallback. + // therefore our screen will be displayed, and if it is approved, at this moment + // the approvedCallback will be called. + uiContext.pendingDisplayPageFn = displayPageFn; + _display_page(); + } else { + displayPageFn(); + } } // Fillers -void force_display(callback_t userAcceptCallback, callback_t userRejectCallback) { - if (uiContext.currentLineCount > 0) { - TRACE("Force page display"); - set_callbacks(userAcceptCallback, userRejectCallback); - _display_page(); - } else { - TRACE("Nothing to do"); - trigger_callback(userAcceptCallback); - } -} - -void fill_and_display_if_required(const char *line1, const char *line2, +void force_display(callback_t userAcceptCallback, callback_t userRejectCallback) +{ + if (uiContext.currentLineCount > 0) { + TRACE("Force page display"); + set_callbacks(userAcceptCallback, userRejectCallback); + _display_page(); + } else { + TRACE("Nothing to do"); + trigger_callback(userAcceptCallback); + } +} + +void fill_and_display_if_required(const char* line1, const char* line2, callback_t userAcceptCallback, - callback_t userRejectCallback) { + callback_t userRejectCallback) +{ - ASSERT(strlen(line1) <= MAX_TAG_TITLE_LINE_LENGTH); - ASSERT(strlen(line2) <= MAX_TAG_CONTENT_LENGTH); + ASSERT(strlen(line1) <= MAX_TAG_TITLE_LINE_LENGTH); + ASSERT(strlen(line2) <= MAX_TAG_CONTENT_LENGTH); - if (uiContext.pendingElement) { - handle_pending_element(); - } + if (uiContext.pendingElement) { + handle_pending_element(); + } - if (uiContext.currentLineCount + get_element_line_count(line2) > - MAX_LINE_PER_PAGE_COUNT) { - TRACE("Display page and add pending element"); - fill_pending_element(line1, line2); - set_callbacks(userAcceptCallback, userRejectCallback); - _display_page(); - } else { - TRACE("Add element to page"); - fill_current_element(line1, line2); - trigger_callback(userAcceptCallback); - } + if (uiContext.currentLineCount + get_element_line_count(line2) > + MAX_LINE_PER_PAGE_COUNT) { + TRACE("Display page and add pending element"); + fill_pending_element(line1, line2); + set_callbacks(userAcceptCallback, userRejectCallback); + _display_page(); + } else { + TRACE("Add element to page"); + fill_current_element(line1, line2); + trigger_callback(userAcceptCallback); + } } -void fill_address_data(char *text, char *content, callback_t callback) { - fill_current_element(text, content); - trigger_callback(callback); +void fill_address_data(char* text, char* content, callback_t callback) +{ + fill_current_element(text, content); + trigger_callback(callback); } -void display_confirmation(const char *text1, const char *text2, - const char *confirmText, const char *rejectText, +void display_confirmation(const char* text1, const char* text2, + const char* confirmText, const char* rejectText, callback_t userAcceptCallback, - callback_t userRejectCallback) { - TRACE("Displaying confirmation"); + callback_t userRejectCallback) +{ + TRACE("Displaying confirmation"); - uiContext.confirmedStatus = (char *)confirmText; - uiContext.rejectedStatus = (char *)rejectText; + uiContext.confirmedStatus = (char*)confirmText; + uiContext.rejectedStatus = (char*)rejectText; - set_callbacks(userAcceptCallback, userRejectCallback); + set_callbacks(userAcceptCallback, userRejectCallback); - strncpy(uiContext.pageText[0], text1, MAX_TEXT_STRING); - strncpy(uiContext.pageText[1], text2, MAX_TEXT_STRING); + strncpy(uiContext.pageText[0], text1, MAX_TEXT_STRING); + strncpy(uiContext.pageText[1], text2, MAX_TEXT_STRING); - if (uiContext.lightConfirmation) { - _display_page_or_call_function(&_display_light_confirmation); - } else { - _display_page_or_call_function(&_display_confirmation); - } + if (uiContext.lightConfirmation) { + _display_page_or_call_function(&_display_light_confirmation); + } else { + _display_page_or_call_function(&_display_confirmation); + } } -void display_prompt(const char *text1, const char *text2, - callback_t userAcceptCallback, callback_t userRejectCallback) { - TRACE("Displaying Prompt"); +void display_prompt(const char* text1, const char* text2, + callback_t userAcceptCallback, callback_t userRejectCallback) +{ + TRACE("Displaying Prompt"); - set_callbacks(userAcceptCallback, userRejectCallback); + set_callbacks(userAcceptCallback, userRejectCallback); - strncpy(uiContext.pageText[0], text1, MAX_TEXT_STRING); - strncpy(uiContext.pageText[1], text2, MAX_TEXT_STRING); + strncpy(uiContext.pageText[0], text1, MAX_TEXT_STRING); + strncpy(uiContext.pageText[1], text2, MAX_TEXT_STRING); - _display_page_or_call_function(&_display_prompt); + _display_page_or_call_function(&_display_prompt); } -void display_warning(const char *text, callback_t userAcceptCallback, - callback_t userRejectCallback) { - TRACE("Displaying Warning"); +void display_warning(const char* text, callback_t userAcceptCallback, + callback_t userRejectCallback) +{ + TRACE("Displaying Warning"); - set_callbacks(userAcceptCallback, userRejectCallback); - strncpy(uiContext.pageText[0], text, MAX_TEXT_STRING); - _display_page_or_call_function(&_display_warning); + set_callbacks(userAcceptCallback, userRejectCallback); + strncpy(uiContext.pageText[0], text, MAX_TEXT_STRING); + _display_page_or_call_function(&_display_warning); } -void display_address(callback_t userAcceptCallback, callback_t userRejectCallback) { - TRACE("Displaying Address"); +void display_address(callback_t userAcceptCallback, callback_t userRejectCallback) +{ + TRACE("Displaying Address"); - set_callbacks(userAcceptCallback, userRejectCallback); - nbgl_useCaseReviewStart(&C_cardano_64, (char *)"Verify Cardano\naddress", - NULL, (char *)"Cancel", display_address_callback, - display_cancel_status); -#ifdef HEADLESS - nbgl_refresh(); - trigger_callback(&display_address_callback); -#endif + set_callbacks(userAcceptCallback, userRejectCallback); + nbgl_useCaseReviewStart(&C_cardano_64, (char*)"Verify Cardano\naddress", + NULL, (char*)"Cancel", display_address_callback, + display_cancel_status); + #ifdef HEADLESS + nbgl_refresh(); + trigger_callback(&display_address_callback); + #endif } -void display_error(void) { - TRACE("Displaying Error"); +void display_error(void) +{ + TRACE("Displaying Error"); - nbgl_reset_transaction_full_context(); - nbgl_useCaseStatus((char *)"An error has occurred", false, ui_idle_flow); + nbgl_reset_transaction_full_context(); + nbgl_useCaseStatus((char*)"An error has occurred", false, ui_idle_flow); } #endif // HAVE_NBGL From 0daeb0e2acc453c6f3713ab388f96417e8bdaed9 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 3 Apr 2023 10:45:38 +0200 Subject: [PATCH 038/105] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e8ca98e3..f1bffe5f 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ APPNAME = "Cardano ADA" APPVERSION_M = 6 APPVERSION_N = 0 -APPVERSION_P = 3 +APPVERSION_P = 4 APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" ifeq ($(BOLOS_SDK),) From 2b2e54367c01aba8f1df825ae42c8d1c1b7ff99d Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 3 Apr 2023 13:51:45 +0200 Subject: [PATCH 039/105] Fix: getPublicKeys: change step to PROMPT --- src/getPublicKeys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/getPublicKeys.c b/src/getPublicKeys.c index dae60f1e..8597ed66 100644 --- a/src/getPublicKeys.c +++ b/src/getPublicKeys.c @@ -61,7 +61,7 @@ void runGetOnePublicKeyUIFlow() switch (policy) { #define CASE(policy, step) case policy: {ctx->ui_step = step; break;} CASE(POLICY_PROMPT_WARN_UNUSUAL, GET_KEY_UI_STEP_WARNING); - CASE(POLICY_PROMPT_BEFORE_RESPONSE, GET_KEY_UI_STEP_DISPLAY); + CASE(POLICY_PROMPT_BEFORE_RESPONSE, GET_KEY_UI_STEP_PROMPT); CASE(POLICY_ALLOW_WITHOUT_PROMPT, GET_KEY_UI_STEP_RESPOND); #undef CASE default: From e34036d66c75bba6a986a8ac5bb151e161dc55bc Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 5 Apr 2023 12:10:54 +0200 Subject: [PATCH 040/105] ui_nbgl: add parameter to control approved status display --- src/ui.h | 1 + src/ui_nbgl.c | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/ui.h b/src/ui.h index 1d3eabbe..2dffc3ed 100644 --- a/src/ui.h +++ b/src/ui.h @@ -13,6 +13,7 @@ void fill_address_data(char* text, char* content, callback_t callback); void fill_and_display_if_required(const char* line1, const char* line2, callback_t user_accept_cb, callback_t user_reject_cb); void force_display(callback_t user_accept_cb, callback_t user_reject_cb); void display_confirmation(const char* text1, const char* text2, const char* confirmText, const char* rejectText, callback_t user_accept_cb, callback_t user_reject_cb); +void display_confirmation_no_approved_status(const char* text1, const char* text2, const char* rejectText, callback_t user_accept_cb, callback_t user_reject_cb); void display_page(callback_t user_accept_cb, callback_t user_reject_cb); void display_prompt(const char* text1, const char* text2, callback_t user_accept_cb, callback_t user_reject_cb); void display_warning(const char* text, callback_t user_accept_cb, callback_t user_reject_cb); diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index 606eb3db..6e165bfb 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -48,6 +48,7 @@ typedef struct { char pageText[2][MAX_TEXT_STRING]; bool lightConfirmation; nbgl_layoutTagValueList_t pairList; + bool no_approved_status; } UiContext_t; static nbgl_page_t* pageContext; @@ -59,6 +60,7 @@ static UiContext_t uiContext = { .currentElementCount = 0, .pendingElement = false, .lightConfirmation = 0, + .no_approved_status = false, }; // Forward declaration @@ -119,6 +121,7 @@ void nbgl_reset_transaction_full_context(void) uiContext.approvedCallback = NULL; uiContext.rejectedCallback = NULL; uiContext.pendingDisplayPageFn = NULL; + uiContext.no_approved_status = false; } void set_light_confirmation(bool needed) @@ -322,7 +325,9 @@ static void display_confirmation_status(void) uiContext.approvedCallback(); } - trigger_callback(&confirmation_status_callback); + if (!uiContext.no_approved_status) { + trigger_callback(&confirmation_status_callback); + } } static void display_address_callback(void) @@ -486,6 +491,15 @@ void display_confirmation(const char* text1, const char* text2, } } +void display_confirmation_no_approved_status(const char* text1, const char* text2, + const char* rejectText, + callback_t userAcceptCallback, + callback_t userRejectCallback) +{ + uiContext.no_approved_status = true; + display_confirmation(text1, text2, NULL, rejectText, userAcceptCallback, userRejectCallback); +} + void display_prompt(const char* text1, const char* text2, callback_t userAcceptCallback, callback_t userRejectCallback) { From 10e6bbdad14a4c61b955cd80a1ed5c4ecef0e29a Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 5 Apr 2023 12:14:11 +0200 Subject: [PATCH 041/105] getPublicKeys_ui: display spinner for stax while we are not done --- src/getPublicKeys_ui.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/getPublicKeys_ui.c b/src/getPublicKeys_ui.c index eb4255bb..d3f65d1c 100644 --- a/src/getPublicKeys_ui.c +++ b/src/getPublicKeys_ui.c @@ -138,8 +138,14 @@ void getPublicKeys_respondOneKey_ui_runStep() ctx->currentPath++; TRACE("Current path: %u / %u", ctx->currentPath, ctx->numPaths); - if (ctx->currentPath == 1 || ctx->currentPath == ctx->numPaths) + if (ctx->currentPath == ctx->numPaths) { advanceStage(); + } else if (ctx->currentPath == 1) { + #ifdef HAVE_NBGL + nbgl_useCaseSpinner("Processing"); + #endif + advanceStage(); + } } UI_STEP_END(UI_STEP_NONE); } From 36df37be2a09960c6b03523af9844ba76774e5d2 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 5 Apr 2023 14:21:22 +0200 Subject: [PATCH 042/105] getPublicKeys: display notification only when needed --- src/getPublicKeys.c | 9 +++++++++ src/getPublicKeys.h | 1 + src/getPublicKeys_ui.c | 8 ++++++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/getPublicKeys.c b/src/getPublicKeys.c index 8597ed66..87fc9666 100644 --- a/src/getPublicKeys.c +++ b/src/getPublicKeys.c @@ -49,6 +49,10 @@ void runGetOnePublicKeyUIFlow() TRACE("Policy: %d", (int) policy); ENSURE_NOT_DENIED(policy); + if (policy > POLICY_ALLOW_WITHOUT_PROMPT) { + ctx->silent_export = false; + } + { // Calculation deriveExtendedPublicKey( @@ -121,6 +125,11 @@ static void getPublicKeys_handleInitAPDU(const uint8_t* wireDataBuffer, size_t w // we ask for confirmation for export of the given number of public keys security_policy_t policy = policyForGetPublicKeysInit(ctx->numPaths); TRACE("Policy: %d", (int) policy); + if (policy == POLICY_PROMPT_BEFORE_RESPONSE) { + ctx->silent_export = false; + } else { + ctx->silent_export = true; + } ENSURE_NOT_DENIED(policy); { // select UI steps diff --git a/src/getPublicKeys.h b/src/getPublicKeys.h index ca02fa8e..6d38c787 100644 --- a/src/getPublicKeys.h +++ b/src/getPublicKeys.h @@ -26,6 +26,7 @@ typedef struct { uint16_t responseReadyMagic; int ui_step; + bool silent_export; } ins_get_keys_context_t; handler_fn_t getPublicKeys_handleAPDU; diff --git a/src/getPublicKeys_ui.c b/src/getPublicKeys_ui.c index d3f65d1c..331634c7 100644 --- a/src/getPublicKeys_ui.c +++ b/src/getPublicKeys_ui.c @@ -116,10 +116,9 @@ void getPublicKeys_respondOneKey_ui_runStep() respond_with_user_reject ); #elif defined(HAVE_NBGL) - display_confirmation( + display_confirmation_no_approved_status( "Confirm\npublic key export", "", - "PUBLIC KEY\nEXPORTED", "Public key\nrejected", this_fn, respond_with_user_reject @@ -139,6 +138,11 @@ void getPublicKeys_respondOneKey_ui_runStep() TRACE("Current path: %u / %u", ctx->currentPath, ctx->numPaths); if (ctx->currentPath == ctx->numPaths) { + #ifdef HAVE_NBGL + if (!ctx->silent_export) { + nbgl_useCaseStatus("PUBLIC KEY\nEXPORTED", true, ui_idle_flow); + } + #endif // HAVE_NBGL advanceStage(); } else if (ctx->currentPath == 1) { #ifdef HAVE_NBGL From 18bfe80289e7791515119c4fb3dd4404992dd3ac Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 5 Apr 2023 16:07:02 +0200 Subject: [PATCH 043/105] [clean] add attributes for intentional fallthrough --- src/addressUtilsShelley.c | 4 ++- src/cbor.c | 2 +- src/getPublicKeys_ui.c | 3 +-- src/io.c | 1 + src/securityPolicy.c | 1 + src/signCVote.c | 1 + src/signTx.c | 44 ++++++++++++--------------------- src/signTxPoolRegistration_ui.c | 6 ++--- src/txHashBuilder.c | 6 ++--- src/uiHelpers.h | 1 + 10 files changed, 29 insertions(+), 40 deletions(-) diff --git a/src/addressUtilsShelley.c b/src/addressUtilsShelley.c index fff8f60e..688c2c54 100644 --- a/src/addressUtilsShelley.c +++ b/src/addressUtilsShelley.c @@ -111,6 +111,7 @@ bool isStakingInfoConsistentWithAddressType(const addressParams_t* addressParams case REWARD_SCRIPT: CONSISTENT_WITH(STAKING_SCRIPT_HASH); + __attribute__((fallthrough)); case POINTER_KEY: case POINTER_SCRIPT: CONSISTENT_WITH(BLOCKCHAIN_POINTER); @@ -507,6 +508,7 @@ size_t humanReadableAddress(const uint8_t* address, size_t addressSize, char* ou case BYRON: ASSERT(false); + __attribute__((fallthrough)); case REWARD_KEY: case REWARD_SCRIPT: if (networkId == TESTNET_NETWORK_ID) @@ -724,7 +726,7 @@ spending_choice_t determineSpendingChoice(address_type_t addressType) default: ASSERT(false); - // intentional fallthrough + __attribute__((fallthrough)); case REWARD_KEY: case REWARD_SCRIPT: return SPENDING_NONE; diff --git a/src/cbor.c b/src/cbor.c index 94c5598d..2ee4721a 100644 --- a/src/cbor.c +++ b/src/cbor.c @@ -135,8 +135,8 @@ size_t cbor_writeToken(uint8_t type, uint64_t value, uint8_t* buffer, size_t buf THROW(ERR_UNEXPECTED_TOKEN); } value = (uint64_t)(-negativeValue) - 1; - // intentional fallthrough } + __attribute__((fallthrough)); case CBOR_TYPE_UNSIGNED: case CBOR_TYPE_BYTES: case CBOR_TYPE_TEXT: diff --git a/src/getPublicKeys_ui.c b/src/getPublicKeys_ui.c index 331634c7..cdfc6c04 100644 --- a/src/getPublicKeys_ui.c +++ b/src/getPublicKeys_ui.c @@ -34,8 +34,7 @@ static void advanceStage() break; } - // intentional fallthrough - + __attribute__((fallthrough)); case GET_KEYS_STAGE_GET_KEYS: ASSERT(ctx->currentPath == ctx->numPaths); ctx->stage = GET_KEYS_STAGE_NONE; diff --git a/src/io.c b/src/io.c index 93fab304..f8b9eac5 100644 --- a/src/io.c +++ b/src/io.c @@ -98,6 +98,7 @@ unsigned char io_event(unsigned char channel MARK_UNUSED) THROW(EXCEPTION_IO_RESET); } + __attribute__((fallthrough)); case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: #ifdef HAVE_BAGL UX_DISPLAYED_EVENT({}); diff --git a/src/securityPolicy.c b/src/securityPolicy.c index 5e613a75..e46cc631 100644 --- a/src/securityPolicy.c +++ b/src/securityPolicy.c @@ -1339,6 +1339,7 @@ security_policy_t policyForSignTxWithdrawal( break; } + __attribute__((fallthrough)); case STAKE_CREDENTIAL_SCRIPT_HASH: switch (txSigningMode) { case SIGN_TX_SIGNINGMODE_MULTISIG_TX: diff --git a/src/signCVote.c b/src/signCVote.c index 1a865a3e..3e63e57c 100644 --- a/src/signCVote.c +++ b/src/signCVote.c @@ -38,6 +38,7 @@ void vote_advanceStage() // vote_advanceStage() not supposed to be called after votecast processing is finished ASSERT(false); + __attribute__((fallthrough)); default: ASSERT(false); diff --git a/src/signTx.c b/src/signTx.c index cacf0bd7..2e6fac40 100644 --- a/src/signTx.c +++ b/src/signTx.c @@ -74,8 +74,7 @@ void tx_advanceStage() break; } - // intentional fallthrough - + __attribute__((fallthrough)); case SIGN_STAGE_AUX_DATA: if (ctx->includeAuxData) { ASSERT(AUX_DATA_CTX->auxDataReceived); @@ -120,8 +119,7 @@ void tx_advanceStage() break; } - // intentional fallthrough - + __attribute__((fallthrough)); case SIGN_STAGE_BODY_OUTPUTS: // we should have received all outputs ASSERT(BODY_CTX->currentOutput == ctx->numOutputs); @@ -138,8 +136,7 @@ void tx_advanceStage() break; } - // intentional fallthrough - + __attribute__((fallthrough)); case SIGN_STAGE_BODY_TTL: if (ctx->includeTtl) { ASSERT(BODY_CTX->ttlReceived); @@ -152,8 +149,7 @@ void tx_advanceStage() break; } - // intentional fallthrough - + __attribute__((fallthrough)); case SIGN_STAGE_BODY_CERTIFICATES: // we should have received all certificates ASSERT(BODY_CTX->currentCertificate == ctx->numCertificates); @@ -165,8 +161,7 @@ void tx_advanceStage() break; } - // intentional fallthrough - + __attribute__((fallthrough)); case SIGN_STAGE_BODY_WITHDRAWALS: // we should have received all withdrawals ASSERT(BODY_CTX->currentWithdrawal == ctx->numWithdrawals); @@ -186,8 +181,7 @@ void tx_advanceStage() break; } - // intentional fallthrough - + __attribute__((fallthrough)); case SIGN_STAGE_BODY_VALIDITY_INTERVAL: if (ctx->includeValidityIntervalStart) { ASSERT(BODY_CTX->validityIntervalStartReceived); @@ -200,8 +194,7 @@ void tx_advanceStage() break; } - // intentional fallthrough - + __attribute__((fallthrough)); case SIGN_STAGE_BODY_MINT: if (ctx->includeMint) { ASSERT(BODY_CTX->mintReceived); @@ -211,8 +204,7 @@ void tx_advanceStage() break; } - // intentional fallthrough - + __attribute__((fallthrough)); case SIGN_STAGE_BODY_SCRIPT_DATA_HASH: if (ctx->includeScriptDataHash) { ASSERT(BODY_CTX->scriptDataHashReceived); @@ -223,8 +215,7 @@ void tx_advanceStage() break; } - // intentional fallthrough - + __attribute__((fallthrough)); case SIGN_STAGE_BODY_COLLATERAL_INPUTS: ASSERT(BODY_CTX->currentCollateral == ctx->numCollateralInputs); ctx->stage = SIGN_STAGE_BODY_REQUIRED_SIGNERS; @@ -233,8 +224,7 @@ void tx_advanceStage() break; } - // intentional fallthrough - + __attribute__((fallthrough)); case SIGN_STAGE_BODY_REQUIRED_SIGNERS: ASSERT(BODY_CTX->currentRequiredSigner == ctx->numRequiredSigners); if (ctx->includeNetworkId) { @@ -246,8 +236,7 @@ void tx_advanceStage() break; } - // intentional fallthrough - + __attribute__((fallthrough)); case SIGN_STAGE_BODY_COLLATERAL_OUTPUT: if (ctx->includeCollateralOutput) { ASSERT(BODY_CTX->collateralOutputReceived); @@ -257,8 +246,7 @@ void tx_advanceStage() break; } - // intentional fallthrough - + __attribute__((fallthrough)); case SIGN_STAGE_BODY_TOTAL_COLLATERAL: if (ctx->includeTotalCollateral) { ASSERT(BODY_CTX->totalCollateralReceived); @@ -269,8 +257,7 @@ void tx_advanceStage() break; } - // intentional fallthrough - + __attribute__((fallthrough)); case SIGN_STAGE_BODY_REFERENCE_INPUTS: ASSERT(BODY_CTX->currentReferenceInput == ctx->numReferenceInputs); ctx->stage = SIGN_STAGE_CONFIRM; @@ -284,8 +271,7 @@ void tx_advanceStage() break; } - // intentional fallthrough - + __attribute__((fallthrough)); case SIGN_STAGE_WITNESSES: ctx->stage = SIGN_STAGE_NONE; ui_idle(); // we are done with this tx @@ -295,6 +281,7 @@ void tx_advanceStage() // tx_advanceStage() not supposed to be called after tx processing is finished ASSERT(false); + __attribute__((fallthrough)); default: ASSERT(false); } @@ -387,6 +374,7 @@ static inline void checkForFinishedSubmachines() tx_advanceStage(); } + __attribute__((fallthrough)); case SIGN_STAGE_BODY_COLLATERAL_OUTPUT_SUBMACHINE: if (isCurrentOutputFinished()) { TRACE(); diff --git a/src/signTxPoolRegistration_ui.c b/src/signTxPoolRegistration_ui.c index 283c0d5b..09e0492a 100644 --- a/src/signTxPoolRegistration_ui.c +++ b/src/signTxPoolRegistration_ui.c @@ -58,8 +58,7 @@ static inline void advanceState() break; } - // intentional fallthrough - + __attribute__((fallthrough)); case STAKE_POOL_REGISTRATION_OWNERS: ASSERT(subctx->currentOwner == subctx->numOwners); @@ -70,8 +69,7 @@ static inline void advanceState() break; } - // intentional fallthrough - + __attribute__((fallthrough)); case STAKE_POOL_REGISTRATION_RELAYS: ASSERT(subctx->currentRelay == subctx->numRelays); diff --git a/src/txHashBuilder.c b/src/txHashBuilder.c index 23d198d3..274b4fb1 100644 --- a/src/txHashBuilder.c +++ b/src/txHashBuilder.c @@ -1214,15 +1214,13 @@ static void addPoolMetadata_updateState(tx_hash_builder_t* builder) ASSERT(builder->poolCertificateData.remainingOwners == 0); txHashBuilder_addPoolRegistrationCertificate_enterOwners(builder); - // intentional fallthrough - + __attribute__((fallthrough)); case TX_HASH_BUILDER_IN_CERTIFICATES_POOL_OWNERS: // skipping relays is only possible if none were expected ASSERT(builder->poolCertificateData.remainingRelays == 0); txHashBuilder_addPoolRegistrationCertificate_enterRelays(builder); - // intentional fallthrough - + __attribute__((fallthrough)); case TX_HASH_BUILDER_IN_CERTIFICATES_POOL_RELAYS: // all relays should have been received ASSERT(builder->poolCertificateData.remainingRelays == 0); diff --git a/src/uiHelpers.h b/src/uiHelpers.h index b9a9bcbd..e8f6e7c3 100644 --- a/src/uiHelpers.h +++ b/src/uiHelpers.h @@ -42,6 +42,7 @@ extern bolos_ux_params_t G_ux_params; #define UI_STEP(NEXT_STEP) \ *__ui_step_ptr = NEXT_STEP; \ } \ + __attribute__((fallthrough)); case NEXT_STEP: { #else #define UI_STEP(NEXT_STEP) \ From 581813dd85dd8cb7275617338030ee01ef7f0610 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 5 Apr 2023 16:26:46 +0200 Subject: [PATCH 044/105] ui_nbgl: remove unnecessary cast --- src/ui_menu_nbgl.c | 8 ++++---- src/ui_nbgl.c | 44 ++++++++++++++++++++++---------------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/ui_menu_nbgl.c b/src/ui_menu_nbgl.c index 98cc9a14..0eee71f3 100644 --- a/src/ui_menu_nbgl.c +++ b/src/ui_menu_nbgl.c @@ -50,8 +50,8 @@ static void exit(void) static bool settings_navigation_callback(uint8_t page, nbgl_pageContent_t* content) { if (page == 0) { - switches[0].text = (char*)"Enable expert mode"; - switches[0].subText = (char*)"Select application mode"; + switches[0].text = "Enable expert mode"; + switches[0].subText = "Select application mode"; switches[0].token = SWITCH_APP_MODE_TOKEN; switches[0].tuneId = TUNE_TAP_CASUAL; switches[0].initState = app_mode_expert(); @@ -86,7 +86,7 @@ static void settings_control_callback(int token, uint8_t index) static void ui_menu_settings(void) { - nbgl_useCaseSettings((char*)"Cardano settings", PAGE_START, NB_PAGE_SETTING, + nbgl_useCaseSettings("Cardano settings", PAGE_START, NB_PAGE_SETTING, IS_TOUCHABLE, ui_idle_flow, settings_navigation_callback, settings_control_callback); } @@ -96,7 +96,7 @@ void ui_idle_flow(void) TRACE("RESETTING\n\n"); // We need to make sure the ui context is reset even if the app restarts nbgl_reset_transaction_full_context(); - nbgl_useCaseHome((char*)"Cardano", &C_cardano_64, NULL, true, + nbgl_useCaseHome("Cardano", &C_cardano_64, NULL, true, ui_menu_settings, exit); } diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index 6e165bfb..3218ad93 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -35,8 +35,8 @@ enum { }; typedef struct { - char* confirmedStatus; // text displayed in confirmation page (after long press) - char* rejectedStatus; // text displayed in rejection page (after reject confirmed) + const char* confirmedStatus; // text displayed in confirmation page (after long press) + const char* rejectedStatus; // text displayed in rejection page (after reject confirmed) callback_t approvedCallback; callback_t rejectedCallback; callback_t pendingDisplayPageFn; @@ -181,7 +181,7 @@ static void _display_confirmation(void) .type = INFO_LONG_PRESS, .infoLongPress.icon = &C_cardano_64, .infoLongPress.text = uiContext.pageText[0], - .infoLongPress.longPressText = (char*)"Hold to approve", + .infoLongPress.longPressText = "Hold to approve", .infoLongPress.longPressToken = CONFIRMATION_STATUS_TOKEN, .infoLongPress.tuneId = TUNE_TAP_NEXT }; @@ -207,8 +207,8 @@ static void _display_light_confirmation(void) { TRACE("_light_confirmation"); - nbgl_useCaseChoice(&C_cardano_64, uiContext.pageText[0], (char*)"", - (char*)"Confirm", (char*)"Cancel", light_confirm_callback); + nbgl_useCaseChoice(&C_cardano_64, uiContext.pageText[0], "", + "Confirm", "Cancel", light_confirm_callback); #ifdef HEADLESS trigger_callback(uiContext.approvedCallback); @@ -220,8 +220,8 @@ static void display_cancel(void) if (uiContext.lightConfirmation) { display_cancel_status(); } else { - nbgl_useCaseConfirm((char*)"Reject ?", NULL, (char*)"Yes, Reject", - (char*)"Go back", display_cancel_status); + nbgl_useCaseConfirm("Reject ?", NULL, "Yes, Reject", + "Go back", display_cancel_status); } } @@ -240,7 +240,7 @@ static void display_cancel_status(void) if (uiContext.rejectedStatus) { nbgl_useCaseStatus(uiContext.rejectedStatus, false, cancellation_status_callback); } else { - nbgl_useCaseStatus((char*)"Action rejected", false, cancellation_status_callback); + nbgl_useCaseStatus("Action rejected", false, cancellation_status_callback); } } @@ -261,9 +261,9 @@ static void _display_page(void) .navType = NAV_WITH_TAP, .progressIndicator = true, .navWithTap.backButton = false, - .navWithTap.nextPageText = (char*)"Tap to continue", + .navWithTap.nextPageText = "Tap to continue", .navWithTap.nextPageToken = ACCEPT_PAGE_TOKEN, - .navWithTap.quitText = (char*)"Cancel", + .navWithTap.quitText = "Cancel", .quitToken = CANCEL_PROMPT_TOKEN, .tuneId = TUNE_TAP_CASUAL }; @@ -288,7 +288,7 @@ static void _display_prompt(void) TRACE("_prompt"); nbgl_useCaseReviewStart(&C_cardano_64, uiContext.pageText[0], - uiContext.pageText[1], (char*)"Reject if not sure", + uiContext.pageText[1], "Reject if not sure", uiContext.approvedCallback, &display_cancel); #ifdef HEADLESS nbgl_refresh(); @@ -300,8 +300,8 @@ static void _display_warning(void) { TRACE("_warning"); - nbgl_useCaseReviewStart(&C_warning64px, (char*)"WARNING", - uiContext.pageText[0], (char*)"Reject if not sure", + nbgl_useCaseReviewStart(&C_warning64px, "WARNING", + uiContext.pageText[0], "Reject if not sure", uiContext.approvedCallback, &display_cancel); #ifdef HEADLESS nbgl_refresh(); @@ -314,7 +314,7 @@ static void confirmation_status_callback(void) if (uiContext.confirmedStatus) { nbgl_useCaseStatus(uiContext.confirmedStatus, true, ui_idle_flow); } else { - nbgl_useCaseStatus((char*)"ACTION\nCONFIRMED", true, ui_idle_flow); + nbgl_useCaseStatus("ACTION\nCONFIRMED", true, ui_idle_flow); } } @@ -338,8 +338,8 @@ static void display_address_callback(void) uiContext.pairList.nbPairs = uiContext.currentElementCount - 1; uiContext.pairList.pairs = tagValues; - uiContext.confirmedStatus = (char*)"ADDRESS\nVERIFIED"; - uiContext.rejectedStatus = (char*)"Address rejected"; + uiContext.confirmedStatus = "ADDRESS\nVERIFIED"; + uiContext.rejectedStatus = "Address rejected"; for (uint8_t i = 0; i < uiContext.currentElementCount; i++) { if (strcmp(uiContext.tagTitle[i], "Address")) { @@ -379,7 +379,7 @@ static void trigger_callback(callback_t userAcceptCallback) layoutDescription.withLeftBorder = true; layoutDescription.onActionCallback = NULL; - layoutDescription.tapActionText = (char*)""; + layoutDescription.tapActionText = ""; layoutDescription.tapActionToken = 0; layoutDescription.tapTuneId = TUNE_TAP_CASUAL; @@ -476,8 +476,8 @@ void display_confirmation(const char* text1, const char* text2, { TRACE("Displaying confirmation"); - uiContext.confirmedStatus = (char*)confirmText; - uiContext.rejectedStatus = (char*)rejectText; + uiContext.confirmedStatus = confirmText; + uiContext.rejectedStatus = rejectText; set_callbacks(userAcceptCallback, userRejectCallback); @@ -528,8 +528,8 @@ void display_address(callback_t userAcceptCallback, callback_t userRejectCallbac TRACE("Displaying Address"); set_callbacks(userAcceptCallback, userRejectCallback); - nbgl_useCaseReviewStart(&C_cardano_64, (char*)"Verify Cardano\naddress", - NULL, (char*)"Cancel", display_address_callback, + nbgl_useCaseReviewStart(&C_cardano_64, "Verify Cardano\naddress", + NULL, "Cancel", display_address_callback, display_cancel_status); #ifdef HEADLESS nbgl_refresh(); @@ -542,7 +542,7 @@ void display_error(void) TRACE("Displaying Error"); nbgl_reset_transaction_full_context(); - nbgl_useCaseStatus((char*)"An error has occurred", false, ui_idle_flow); + nbgl_useCaseStatus("An error has occurred", false, ui_idle_flow); } #endif // HAVE_NBGL From 393d1f86d6f79b7f40368e6ed7bae61cf927bbc1 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 5 Apr 2023 16:33:44 +0200 Subject: [PATCH 045/105] nbgl: use defines from SDK --- src/ui_nbgl.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index 3218ad93..f0798c79 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -21,13 +21,12 @@ #include "uiHelpers.h" #include "uiScreens_nbgl.h" -#define MAX_LINE_PER_PAGE_COUNT 10 +#define MAX_LINE_PER_PAGE_COUNT NB_MAX_LINES_IN_REVIEW #define MAX_TAG_CONTENT_CHAR_PER_LINE 18 -#define MAX_TAG_PER_PAGE_COUNT 4 #define MAX_TAG_TITLE_LINE_LENGTH 30 #define MAX_TAG_CONTENT_LENGTH 200 #define MAX_TEXT_STRING 50 -#define PENDING_ELEMENT_INDEX MAX_TAG_PER_PAGE_COUNT +#define PENDING_ELEMENT_INDEX NB_MAX_DISPLAYED_PAIRS_IN_REVIEW enum { CANCEL_PROMPT_TOKEN = 1, ACCEPT_PAGE_TOKEN, @@ -43,8 +42,8 @@ typedef struct { bool pendingElement; uint8_t currentLineCount; uint8_t currentElementCount; - char tagTitle[MAX_TAG_PER_PAGE_COUNT + 1][MAX_TAG_TITLE_LINE_LENGTH]; - char tagContent[MAX_TAG_PER_PAGE_COUNT + 1][MAX_TAG_CONTENT_LENGTH]; + char tagTitle[NB_MAX_DISPLAYED_PAIRS_IN_REVIEW + 1][MAX_TAG_TITLE_LINE_LENGTH]; + char tagContent[NB_MAX_DISPLAYED_PAIRS_IN_REVIEW + 1][MAX_TAG_CONTENT_LENGTH]; char pageText[2][MAX_TEXT_STRING]; bool lightConfirmation; nbgl_layoutTagValueList_t pairList; From 647d8b385ee409564f16dd027e0284722cc1ea74 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 12 Apr 2023 09:13:13 +0200 Subject: [PATCH 046/105] [Fix]: add missing breaks --- src/securityPolicy.c | 2 +- src/signTx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/securityPolicy.c b/src/securityPolicy.c index e46cc631..a7cfa4bc 100644 --- a/src/securityPolicy.c +++ b/src/securityPolicy.c @@ -1338,8 +1338,8 @@ security_policy_t policyForSignTxWithdrawal( ASSERT(false); break; } + break; - __attribute__((fallthrough)); case STAKE_CREDENTIAL_SCRIPT_HASH: switch (txSigningMode) { case SIGN_TX_SIGNINGMODE_MULTISIG_TX: diff --git a/src/signTx.c b/src/signTx.c index 2e6fac40..c9a99c77 100644 --- a/src/signTx.c +++ b/src/signTx.c @@ -373,8 +373,8 @@ static inline void checkForFinishedSubmachines() BODY_CTX->mintReceived = true; tx_advanceStage(); } + break; - __attribute__((fallthrough)); case SIGN_STAGE_BODY_COLLATERAL_OUTPUT_SUBMACHINE: if (isCurrentOutputFinished()) { TRACE(); From bc432fdd585ac24a9750256a772e7faec2dd217c Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Wed, 19 Apr 2023 16:50:55 +0200 Subject: [PATCH 047/105] fix load in makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f1bffe5f..bb9370d9 100644 --- a/Makefile +++ b/Makefile @@ -176,7 +176,7 @@ PIN = 5555 APP_LOAD_PARAMS =--appFlags 0x240 --curve ed25519 --path "44'/1815'" --path "1852'/1815'" --path "1853'/1815'" --path "1854'/1815'" --path "1855'/1815'" --path "1694'/1815'" APP_LOAD_PARAMS += $(COMMON_LOAD_PARAMS) -load: all +load: python -m ledgerblue.loadApp $(APP_LOAD_PARAMS) delete: From aeecbdbdfa1194615a1c1a4ffd114b41d93dbc34 Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Wed, 15 Mar 2023 10:20:16 +0100 Subject: [PATCH 048/105] refactor: native script hash --- src/deriveNativeScriptHash_ui.c | 259 ++++++++++++++++---------------- src/uiHelpers.h | 2 - 2 files changed, 132 insertions(+), 129 deletions(-) diff --git a/src/deriveNativeScriptHash_ui.c b/src/deriveNativeScriptHash_ui.c index 32c0c055..99bb51c7 100644 --- a/src/deriveNativeScriptHash_ui.c +++ b/src/deriveNativeScriptHash_ui.c @@ -95,6 +95,135 @@ static void deriveScriptHash_display_ui_runStep_cb(void) } #endif // HAVE_NBGL +static void _displayScriptContent(ui_callback_fn_t* this_fn) +{ + switch (ctx->ui_scriptType) { + case UI_SCRIPT_PUBKEY_PATH: { + #ifdef HAVE_BAGL + ui_displayPathScreen( + HEADER, + &ctx->scriptContent.pubkeyPath, + this_fn + ); + #elif defined(HAVE_NBGL) + char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; + ui_getPathScreen(pathStr, SIZEOF(pathStr), &ctx->scriptContent.pubkeyPath); + fill_and_display_if_required("Pubkey path", pathStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL + break; + } + case UI_SCRIPT_PUBKEY_HASH: { + #ifdef HAVE_BAGL + ui_displayBech32Screen( + HEADER, + "addr_shared_vkh", + ctx->scriptContent.pubkeyHash, + ADDRESS_KEY_HASH_LENGTH, + this_fn + ); + #elif defined(HAVE_NBGL) + char encodedStr[BECH32_STRING_SIZE_MAX] = {0}; + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "addr_shared_vkh", ctx->scriptContent.pubkeyHash, ADDRESS_KEY_HASH_LENGTH); + fill_and_display_if_required("Pubkey hash", encodedStr, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL + break; + } + case UI_SCRIPT_ALL: + case UI_SCRIPT_ANY: { + // max possible length 35: "Contains n nested scripts." + // where n is 2^32-1 + char text[37] = {0}; + explicit_bzero(text, SIZEOF(text)); + STATIC_ASSERT(sizeof(ctx->complexScripts[ctx->level].remainingScripts) <= sizeof(unsigned), "oversized type for %u"); + STATIC_ASSERT(!IS_SIGNED(ctx->complexScripts[ctx->level].remainingScripts), "signed type for %u"); + #ifdef HAVE_BAGL + snprintf(text, SIZEOF(text), "Contains %u nested scripts.", ctx->complexScripts[ctx->level].remainingScripts); + // make sure all the information is displayed to the user + ASSERT(strlen(text) + 1 < SIZEOF(text)); + + ui_displayPaginatedText( + HEADER, + text, + this_fn + ); + #elif defined(HAVE_NBGL) + snprintf(text, SIZEOF(text), "%u nested scripts", ctx->complexScripts[ctx->level].remainingScripts); + // make sure all the information is displayed to the user + ASSERT(strlen(text) + 1 < SIZEOF(text)); + fill_and_display_if_required("Content", text, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL + break; + } + case UI_SCRIPT_N_OF_K: { + STATIC_ASSERT(sizeof(ctx->scriptContent.requiredScripts) <= sizeof(unsigned), "oversized type for %u"); + STATIC_ASSERT(!IS_SIGNED(ctx->scriptContent.requiredScripts), "signed type for %u"); + STATIC_ASSERT(sizeof(ctx->complexScripts[ctx->level].remainingScripts) <= sizeof(unsigned), "oversized type for %u"); + STATIC_ASSERT(!IS_SIGNED(ctx->complexScripts[ctx->level].remainingScripts), "signed type for %u"); + // max possible length 85: "Requires n out of k signatures. Contains k nested scripts." + // where n and k is 2^32-1 + char text[87] = {0}; + #ifdef HAVE_BAGL + explicit_bzero(text, SIZEOF(text)); + snprintf(text, SIZEOF(text), "Requires %u out of %u signatures. Contains %u nested scripts", ctx->scriptContent.requiredScripts, ctx->complexScripts[ctx->level].remainingScripts, ctx->complexScripts[ctx->level].remainingScripts); + // make sure all the information is displayed to the user + ASSERT(strlen(text) + 1 < SIZEOF(text)); + + ui_displayPaginatedText( + HEADER, + text, + this_fn + ); + #elif defined(HAVE_NBGL) + explicit_bzero(text, SIZEOF(text)); + snprintf(text, SIZEOF(text), "%u out of %u signatures", ctx->scriptContent.requiredScripts, ctx->complexScripts[ctx->level].remainingScripts); + // make sure all the information is displayed to the user + ASSERT(strlen(text) + 1 < SIZEOF(text)); + fill_and_display_if_required("Requirement", text, deriveScriptHash_display_ui_runStep_cb, respond_with_user_reject); + #endif // HAVE_BAGL + break; + } + case UI_SCRIPT_INVALID_BEFORE: { + #ifdef HAVE_BAGL + ui_displayUint64Screen( + HEADER, + ctx->scriptContent.timelock, + this_fn + ); + #elif defined(HAVE_NBGL) + char line[30]; + ui_getUint64Screen( + line, + SIZEOF(line), + ctx->scriptContent.timelock + ); + fill_and_display_if_required("Invalid before", line, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL + break; + } + + case UI_SCRIPT_INVALID_HEREAFTER: { + #ifdef HAVE_BAGL + ui_displayUint64Screen( + HEADER, + ctx->scriptContent.timelock, + this_fn + ); + #elif defined(HAVE_NBGL) + char line[30]; + ui_getUint64Screen( + line, + SIZEOF(line), + ctx->scriptContent.timelock + ); + fill_and_display_if_required("Invalid hereafter", line, this_fn, respond_with_user_reject); + #endif // HAVE_BAGL + break; + } + default: + ASSERT(false); + } +} + void deriveScriptHash_display_ui_runStep() { TRACE("ui_step = %d", ctx->ui_step); @@ -143,138 +272,14 @@ void deriveScriptHash_display_ui_runStep() fill_and_display_if_required("Script type", "Invalid hereafter", this_fn, respond_with_user_reject); break; default: - THROW(ERR_INVALID_STATE); + ASSERT(false); } } #endif // HAVE_NBGL UI_STEP(DISPLAY_UI_STEP_SCRIPT_CONTENT) { TRACE("ui_scriptType = %d", ctx->ui_scriptType); - switch (ctx->ui_scriptType) { - case UI_SCRIPT_PUBKEY_PATH: { - #ifdef HAVE_BAGL - ui_displayPathScreen( - HEADER, - &ctx->scriptContent.pubkeyPath, - this_fn - ); - #elif defined(HAVE_NBGL) - char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; - ui_getPathScreen(pathStr, SIZEOF(pathStr), &ctx->scriptContent.pubkeyPath); - fill_and_display_if_required("Pubkey path", pathStr, this_fn, respond_with_user_reject); - #endif // HAVE_BAGL - break; - } - case UI_SCRIPT_PUBKEY_HASH: { - #ifdef HAVE_BAGL - ui_displayBech32Screen( - HEADER, - "addr_shared_vkh", - ctx->scriptContent.pubkeyHash, - ADDRESS_KEY_HASH_LENGTH, - this_fn - ); - #elif defined(HAVE_NBGL) - char encodedStr[BECH32_STRING_SIZE_MAX] = {0}; - ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "addr_shared_vkh", ctx->scriptContent.pubkeyHash, ADDRESS_KEY_HASH_LENGTH); - fill_and_display_if_required("Pubkey hash", encodedStr, this_fn, respond_with_user_reject); - #endif // HAVE_BAGL - break; - } - case UI_SCRIPT_ALL: - case UI_SCRIPT_ANY: { - // max possible length 35: "Contains n nested scripts." - // where n is 2^32-1 - char text[37] = {0}; - explicit_bzero(text, SIZEOF(text)); - STATIC_ASSERT(sizeof(ctx->complexScripts[ctx->level].remainingScripts) <= sizeof(unsigned), "oversized type for %u"); - STATIC_ASSERT(!IS_SIGNED(ctx->complexScripts[ctx->level].remainingScripts), "signed type for %u"); - #ifdef HAVE_BAGL - snprintf(text, SIZEOF(text), "Contains %u nested scripts.", ctx->complexScripts[ctx->level].remainingScripts); - // make sure all the information is displayed to the user - ASSERT(strlen(text) + 1 < SIZEOF(text)); - - ui_displayPaginatedText( - HEADER, - text, - this_fn - ); - #elif defined(HAVE_NBGL) - snprintf(text, SIZEOF(text), "%u nested scripts", ctx->complexScripts[ctx->level].remainingScripts); - // make sure all the information is displayed to the user - ASSERT(strlen(text) + 1 < SIZEOF(text)); - fill_and_display_if_required("Content", text, this_fn, respond_with_user_reject); - #endif // HAVE_BAGL - break; - } - case UI_SCRIPT_N_OF_K: { - STATIC_ASSERT(sizeof(ctx->scriptContent.requiredScripts) <= sizeof(unsigned), "oversized type for %u"); - STATIC_ASSERT(!IS_SIGNED(ctx->scriptContent.requiredScripts), "signed type for %u"); - STATIC_ASSERT(sizeof(ctx->complexScripts[ctx->level].remainingScripts) <= sizeof(unsigned), "oversized type for %u"); - STATIC_ASSERT(!IS_SIGNED(ctx->complexScripts[ctx->level].remainingScripts), "signed type for %u"); - // max possible length 85: "Requires n out of k signatures. Contains k nested scripts." - // where n and k is 2^32-1 - char text[87] = {0}; - #ifdef HAVE_BAGL - explicit_bzero(text, SIZEOF(text)); - snprintf(text, SIZEOF(text), "Requires %u out of %u signatures. Contains %u nested scripts", ctx->scriptContent.requiredScripts, ctx->complexScripts[ctx->level].remainingScripts, ctx->complexScripts[ctx->level].remainingScripts); - // make sure all the information is displayed to the user - ASSERT(strlen(text) + 1 < SIZEOF(text)); - - ui_displayPaginatedText( - HEADER, - text, - this_fn - ); - #elif defined(HAVE_NBGL) - explicit_bzero(text, SIZEOF(text)); - snprintf(text, SIZEOF(text), "%u out of %u signatures", ctx->scriptContent.requiredScripts, ctx->complexScripts[ctx->level].remainingScripts); - // make sure all the information is displayed to the user - ASSERT(strlen(text) + 1 < SIZEOF(text)); - fill_and_display_if_required("Requirement", text, deriveScriptHash_display_ui_runStep_cb, respond_with_user_reject); - #endif // HAVE_BAGL - break; - } - case UI_SCRIPT_INVALID_BEFORE: { - #ifdef HAVE_BAGL - ui_displayUint64Screen( - HEADER, - ctx->scriptContent.timelock, - this_fn - ); - #elif defined(HAVE_NBGL) - char line[30]; - ui_getUint64Screen( - line, - SIZEOF(line), - ctx->scriptContent.timelock - ); - fill_and_display_if_required("Invalid before", line, this_fn, respond_with_user_reject); - #endif // HAVE_BAGL - break; - } - - case UI_SCRIPT_INVALID_HEREAFTER: { - #ifdef HAVE_BAGL - ui_displayUint64Screen( - HEADER, - ctx->scriptContent.timelock, - this_fn - ); - #elif defined(HAVE_NBGL) - char line[30]; - ui_getUint64Screen( - line, - SIZEOF(line), - ctx->scriptContent.timelock - ); - fill_and_display_if_required("Invalid hereafter", line, this_fn, respond_with_user_reject); - #endif // HAVE_BAGL - break; - } - default: - THROW(ERR_INVALID_STATE); - } + _displayScriptContent(this_fn); } UI_STEP(DISPLAY_UI_STEP_RESPOND) { @@ -286,8 +291,8 @@ void deriveScriptHash_display_ui_runStep() UI_STEP_END(DISPLAY_UI_STEP_INVALID); } -// Whole native script finish +// Whole native script finish void deriveNativeScriptHash_displayNativeScriptHash_callback() { io_send_buf(SUCCESS, ctx->scriptHashBuffer, SCRIPT_HASH_LENGTH); diff --git a/src/uiHelpers.h b/src/uiHelpers.h index e8f6e7c3..b7627844 100644 --- a/src/uiHelpers.h +++ b/src/uiHelpers.h @@ -67,8 +67,6 @@ extern bolos_ux_params_t G_ux_params; return; \ } -// *INDENT-ON* - typedef enum { CALLBACK_NOT_RUN, CALLBACK_RUN, From e7a2b6572334f261332a01490deb0eb6bd365254 Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Thu, 20 Apr 2023 12:16:52 +0200 Subject: [PATCH 049/105] refactor: get public keys --- src/getPublicKeys.c | 38 +++++++++++++++++++++++++++++++++----- src/getPublicKeys.h | 2 ++ src/getPublicKeys_ui.c | 36 ++---------------------------------- src/getPublicKeys_ui.h | 4 ++++ src/signCVote.c | 3 +-- src/signTx.c | 2 +- 6 files changed, 43 insertions(+), 42 deletions(-) diff --git a/src/getPublicKeys.c b/src/getPublicKeys.c index 87fc9666..dc2cee7f 100644 --- a/src/getPublicKeys.c +++ b/src/getPublicKeys.c @@ -14,10 +14,6 @@ static int16_t RESPONSE_READY_MAGIC = 23456; static ins_get_keys_context_t* ctx = &(instructionState.getKeysContext); -// ctx->ui_state is shared between the intertwined UI state machines below -// it should be set to this value at the beginning and after a UI state machine is finished -static int UI_STEP_NONE = 0; - // this is supposed to be called at the beginning of each APDU handler static inline void CHECK_STAGE(get_keys_stage_t expected) { @@ -25,6 +21,38 @@ static inline void CHECK_STAGE(get_keys_stage_t expected) VALIDATE(ctx->stage == expected, ERR_INVALID_STATE); } +void keys_advanceStage() +{ + TRACE("Advancing from stage: %d", ctx->stage); + + switch (ctx->stage) { + + case GET_KEYS_STAGE_INIT: + ctx->stage = GET_KEYS_STAGE_GET_KEYS; + + if (ctx->numPaths > 1) { + // there are more paths to be received + // so we don't want to advance beyond GET_KEYS_STAGE_GET_KEYS + break; + } + + __attribute__((fallthrough)); + case GET_KEYS_STAGE_GET_KEYS: + ASSERT(ctx->currentPath == ctx->numPaths); + ctx->stage = GET_KEYS_STAGE_NONE; + ui_idle(); // we are done with this key export + break; + + case GET_KEYS_STAGE_NONE: + // vote_advanceStage() not supposed to be called after votecast processing is finished + ASSERT(false); + break; + + default: + ASSERT(false); + } +} + // read a path from view into ctx->pathSpec static void parsePath(read_view_t* view) { @@ -33,7 +61,7 @@ static void parsePath(read_view_t* view) PRINTF("\n"); } -// ============================== derivation and UI state machine for one key ============================== +// ============================== derivation for one key ============================== // derive the key described by ctx->pathSpec and run the ui state machine accordingly void runGetOnePublicKeyUIFlow() diff --git a/src/getPublicKeys.h b/src/getPublicKeys.h index 6d38c787..f491485e 100644 --- a/src/getPublicKeys.h +++ b/src/getPublicKeys.h @@ -32,4 +32,6 @@ typedef struct { handler_fn_t getPublicKeys_handleAPDU; void runGetOnePublicKeyUIFlow(); +void keys_advanceStage(); + #endif // H_CARDANO_APP_GET_PUBLIC_KEYS diff --git a/src/getPublicKeys_ui.c b/src/getPublicKeys_ui.c index cdfc6c04..bc2368ab 100644 --- a/src/getPublicKeys_ui.c +++ b/src/getPublicKeys_ui.c @@ -15,38 +15,6 @@ static int16_t RESPONSE_READY_MAGIC = 23456; static ins_get_keys_context_t* ctx = &(instructionState.getKeysContext); -// ctx->ui_state is shared between the intertwined UI state machines below -// it should be set to this value at the beginning and after a UI state machine is finished -static int UI_STEP_NONE = 0; - -static void advanceStage() -{ - TRACE("Advancing from stage: %d", ctx->stage); - - switch (ctx->stage) { - - case GET_KEYS_STAGE_INIT: - ctx->stage = GET_KEYS_STAGE_GET_KEYS; - - if (ctx->numPaths > 1) { - // there are more paths to be received - // so we don't want to advance beyond GET_KEYS_STAGE_GET_KEYS - break; - } - - __attribute__((fallthrough)); - case GET_KEYS_STAGE_GET_KEYS: - ASSERT(ctx->currentPath == ctx->numPaths); - ctx->stage = GET_KEYS_STAGE_NONE; - ui_idle(); // we are done with this key export - break; - - case SIGN_STAGE_NONE: - default: - ASSERT(false); - } -} - // ============================== derivation and UI state machine for one key ============================== #ifdef HAVE_NBGL @@ -142,12 +110,12 @@ void getPublicKeys_respondOneKey_ui_runStep() nbgl_useCaseStatus("PUBLIC KEY\nEXPORTED", true, ui_idle_flow); } #endif // HAVE_NBGL - advanceStage(); + keys_advanceStage(); } else if (ctx->currentPath == 1) { #ifdef HAVE_NBGL nbgl_useCaseSpinner("Processing"); #endif - advanceStage(); + keys_advanceStage(); } } UI_STEP_END(UI_STEP_NONE); diff --git a/src/getPublicKeys_ui.h b/src/getPublicKeys_ui.h index 2132a382..f6ea1427 100644 --- a/src/getPublicKeys_ui.h +++ b/src/getPublicKeys_ui.h @@ -1,6 +1,10 @@ #ifndef H_CARDANO_APP_GET_PUBLIC_KEYS_UI #define H_CARDANO_APP_GET_PUBLIC_KEYS_UI +// ctx->ui_state is shared between the intertwined UI state machines +// it should be set to this value at the beginning and after a UI state machine is finished +static int UI_STEP_NONE = 0; + // ============================== derivation and UI state machine for one key ============================== enum { diff --git a/src/signCVote.c b/src/signCVote.c index 3e63e57c..5cdb7b70 100644 --- a/src/signCVote.c +++ b/src/signCVote.c @@ -37,11 +37,10 @@ void vote_advanceStage() case VOTECAST_STAGE_NONE: // vote_advanceStage() not supposed to be called after votecast processing is finished ASSERT(false); + break; - __attribute__((fallthrough)); default: ASSERT(false); - } TRACE("Advancing cip36 voting stage to: %d", ctx->stage); diff --git a/src/signTx.c b/src/signTx.c index c9a99c77..6fa93dca 100644 --- a/src/signTx.c +++ b/src/signTx.c @@ -280,8 +280,8 @@ void tx_advanceStage() case SIGN_STAGE_NONE: // tx_advanceStage() not supposed to be called after tx processing is finished ASSERT(false); + break; - __attribute__((fallthrough)); default: ASSERT(false); } From 0f4cf708c61851f5d5e2e27e5a79cdaf96deb7f7 Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Thu, 20 Apr 2023 14:26:30 +0200 Subject: [PATCH 050/105] refactor: named constants --- src/cardano.h | 2 +- src/deriveNativeScriptHash_ui.c | 2 +- src/signCVote_ui.c | 2 +- src/signTxCVoteRegistration_ui.c | 2 +- src/signTxMint_ui.c | 2 +- src/signTx_ui.c | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/cardano.h b/src/cardano.h index cf79bccb..f0cfe29b 100644 --- a/src/cardano.h +++ b/src/cardano.h @@ -25,7 +25,7 @@ STATIC_ASSERT(LOVELACE_MAX_SUPPLY < LOVELACE_INVALID, "bad LOVELACE_INVALID"); #define SCRIPT_DATA_HASH_LENGTH 32 #define OUTPUT_DATUM_HASH_LENGTH 32 -#define MINTING_POLICY_ID_SIZE 28 +#define MINTING_POLICY_ID_SIZE (SCRIPT_HASH_LENGTH) #define ASSET_NAME_SIZE_MAX 32 #define REWARD_ACCOUNT_SIZE (1 + ADDRESS_KEY_HASH_LENGTH) diff --git a/src/deriveNativeScriptHash_ui.c b/src/deriveNativeScriptHash_ui.c index 99bb51c7..716d3023 100644 --- a/src/deriveNativeScriptHash_ui.c +++ b/src/deriveNativeScriptHash_ui.c @@ -333,7 +333,7 @@ void deriveNativeScriptHash_displayNativeScriptHash_policyId() deriveNativeScriptHash_displayNativeScriptHash_callback ); #elif defined(HAVE_NBGL) - char bufferHex[2 * 32 + 1] = {0}; + char bufferHex[2 * SCRIPT_HASH_LENGTH + 1] = {0}; ui_getHexBufferScreen(bufferHex, SIZEOF(bufferHex), ctx->scriptHashBuffer, SCRIPT_HASH_LENGTH); fill_and_display_if_required("Policy ID", bufferHex, deriveNativeScriptHash_displayNativeScriptHash_finish, respond_with_user_reject); #endif // HAVE_BAGL diff --git a/src/signCVote_ui.c b/src/signCVote_ui.c index 3ed67bdd..be0fe563 100644 --- a/src/signCVote_ui.c +++ b/src/signCVote_ui.c @@ -44,7 +44,7 @@ void handleInit_ui_runStep() this_fn ); #elif defined(HAVE_NBGL) - char bufferHex[2 * 32 + 1] = {0}; + char bufferHex[2 * VOTE_PLAN_ID_SIZE + 1] = {0}; ui_getHexBufferScreen(bufferHex, SIZEOF(bufferHex), ctx->votePlanId, SIZEOF(ctx->votePlanId)); fill_and_display_if_required("Vote plan id", bufferHex, this_fn, respond_with_user_reject); #endif // HAVE_BAGL diff --git a/src/signTxCVoteRegistration_ui.c b/src/signTxCVoteRegistration_ui.c index 72b16aee..137a55ab 100644 --- a/src/signTxCVoteRegistration_ui.c +++ b/src/signTxCVoteRegistration_ui.c @@ -364,7 +364,7 @@ void signTxCVoteRegistration_handleConfirm_ui_runStep() this_fn ); #elif defined(HAVE_NBGL) - char bufferHex[2 * 32 + 1] = {0}; + char bufferHex[2 * AUX_DATA_HASH_LENGTH + 1] = {0}; ui_getHexBufferScreen(bufferHex, SIZEOF(bufferHex), subctx->auxDataHash, SIZEOF(subctx->auxDataHash)); fill_and_display_if_required("Auxiliary data hash", bufferHex, this_fn, respond_with_user_reject); #endif // HAVE_BAGL diff --git a/src/signTxMint_ui.c b/src/signTxMint_ui.c index da7211f3..5638b5e8 100644 --- a/src/signTxMint_ui.c +++ b/src/signTxMint_ui.c @@ -67,6 +67,7 @@ static inline void advanceState() TRACE("Advancing mint state to: %d", subctx->state); } + __noinline_due_to_stack__ void signTxMint_handleTopLevelData_ui_runStep() { @@ -96,7 +97,6 @@ void signTxMint_handleTopLevelData_ui_runStep() } UI_STEP(HANDLE_MINT_TOP_LEVEL_DATA_RESPOND) { respondSuccessEmptyMsg(); - advanceState(); } UI_STEP_END(HANDLE_MINT_TOP_LEVEL_DATA_INVALID); diff --git a/src/signTx_ui.c b/src/signTx_ui.c index 5bf227e2..dbc386c8 100644 --- a/src/signTx_ui.c +++ b/src/signTx_ui.c @@ -213,7 +213,7 @@ void signTx_handleAuxDataArbitraryHash_ui_runStep() this_fn ); #elif defined(HAVE_NBGL) - char bufferHex[2 * 32 + 1] = {0}; + char bufferHex[2 * AUX_DATA_HASH_LENGTH + 1] = {0}; ui_getHexBufferScreen(bufferHex, SIZEOF(bufferHex), ctx->auxDataHash, SIZEOF(ctx->auxDataHash)); fill_and_display_if_required("Auxiliary data hash", bufferHex, this_fn, respond_with_user_reject); #endif // HAVE_BAGL @@ -844,7 +844,7 @@ void signTx_handleConfirm_ui_runStep() this_fn ); #elif defined(HAVE_NBGL) - char bufferHex[2 * 32 + 1] = {0}; + char bufferHex[2 * TX_HASH_LENGTH + 1] = {0}; ui_getHexBufferScreen(bufferHex, SIZEOF(bufferHex), ctx->txHash, SIZEOF(ctx->txHash)); fill_and_display_if_required("Transaction id", bufferHex, this_fn, respond_with_user_reject); #endif // HAVE_BAGL From 981a9caec74e295d622e5a15f94c19c4da5b8918 Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Fri, 21 Apr 2023 00:52:50 +0200 Subject: [PATCH 051/105] refactor: advanceCertificatesStateIfAppropriate --- src/signTx.c | 4 ++-- src/signTx.h | 2 ++ src/signTx_ui.c | 30 ++---------------------------- 3 files changed, 6 insertions(+), 30 deletions(-) diff --git a/src/signTx.c b/src/signTx.c index 6fa93dca..456245ab 100644 --- a/src/signTx.c +++ b/src/signTx.c @@ -291,7 +291,7 @@ void tx_advanceStage() // called from main state machine when a pool registration certificate // sub-machine is finished, or when other type of certificate is processed -static inline void advanceCertificatesStateIfAppropriate() +void tx_advanceCertificatesStateIfAppropriate() { TRACE("%u", ctx->stage); @@ -348,7 +348,7 @@ static inline void checkForFinishedSubmachines() ASSERT(BODY_CTX->currentCertificate < ctx->numCertificates); ctx->stage = SIGN_STAGE_BODY_CERTIFICATES; - advanceCertificatesStateIfAppropriate(); + tx_advanceCertificatesStateIfAppropriate(); } break; diff --git a/src/signTx.h b/src/signTx.h index cfcd50c0..32a8751b 100644 --- a/src/signTx.h +++ b/src/signTx.h @@ -255,4 +255,6 @@ static inline bool signTx_parseIncluded(uint8_t value) // advances the stage of the main state machine void tx_advanceStage(void); +void tx_advanceCertificatesStateIfAppropriate(); + #endif // H_CARDANO_APP_SIGN_TX diff --git a/src/signTx_ui.c b/src/signTx_ui.c index dbc386c8..6c0a1bdb 100644 --- a/src/signTx_ui.c +++ b/src/signTx_ui.c @@ -344,32 +344,6 @@ void signTx_handleTtl_ui_runStep() // ============================== CERTIFICATES ============================== -// called from main state machine when a pool registration certificate -// sub-machine is finished, or when other type of certificate is processed -static inline void advanceCertificatesStateIfAppropriate() -{ - TRACE("%u", ctx->stage); - - switch (ctx->stage) { - - case SIGN_STAGE_BODY_CERTIFICATES: { - ASSERT(BODY_CTX->currentCertificate < ctx->numCertificates); - - // Advance stage to the next certificate - ASSERT(BODY_CTX->currentCertificate < ctx->numCertificates); - BODY_CTX->currentCertificate++; - - if (BODY_CTX->currentCertificate == ctx->numCertificates) { - tx_advanceStage(); - } - } - break; - - default: - ASSERT(ctx->stage == SIGN_STAGE_BODY_CERTIFICATES_POOL_SUBMACHINE); - } -} - #ifdef HAVE_NBGL static void signTx_handleCertificate_ui_delegation_cb(void) { @@ -539,7 +513,7 @@ void signTx_handleCertificate_ui_runStep() UI_STEP(HANDLE_CERTIFICATE_STEP_RESPOND) { respondSuccessEmptyMsg(); - advanceCertificatesStateIfAppropriate(); + tx_advanceCertificatesStateIfAppropriate(); } UI_STEP_END(HANDLE_CERTIFICATE_STEP_INVALID); } @@ -600,7 +574,7 @@ void signTx_handleCertificatePoolRetirement_ui_runStep() UI_STEP(HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_RESPOND) { respondSuccessEmptyMsg(); - advanceCertificatesStateIfAppropriate(); + tx_advanceCertificatesStateIfAppropriate(); } UI_STEP_END(HANDLE_CERTIFICATE_POOL_RETIREMENT_STEP_INVALID); } From abb9675b19b448f3fbbbb280f30fe0732336595f Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Fri, 21 Apr 2023 12:22:16 +0200 Subject: [PATCH 052/105] fix: a typo in UI msg --- src/getPublicKeys_ui.c | 2 +- src/signTxCVoteRegistration_ui.c | 2 +- src/signTx_ui.c | 2 +- src/uiScreens_nbgl.c | 2 +- src/uiScreens_nbgl.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/getPublicKeys_ui.c b/src/getPublicKeys_ui.c index bc2368ab..8cbc8809 100644 --- a/src/getPublicKeys_ui.c +++ b/src/getPublicKeys_ui.c @@ -61,7 +61,7 @@ void getPublicKeys_respondOneKey_ui_runStep() if (showAccountDescription) { char line1[30]; char line2[30]; - ui_getAccountScreeen( + ui_getAccountScreen( line1, SIZEOF(line1), line2, diff --git a/src/signTxCVoteRegistration_ui.c b/src/signTxCVoteRegistration_ui.c index 137a55ab..49f33fc4 100644 --- a/src/signTxCVoteRegistration_ui.c +++ b/src/signTxCVoteRegistration_ui.c @@ -185,7 +185,7 @@ void signTxCVoteRegistration_handleStakingKey_ui_runStep() if (showAccountDescription) { char line1[30]; char line2[30]; - ui_getAccountScreeen( + ui_getAccountScreen( line1, SIZEOF(line1), line2, diff --git a/src/signTx_ui.c b/src/signTx_ui.c index 6c0a1bdb..d5636f8b 100644 --- a/src/signTx_ui.c +++ b/src/signTx_ui.c @@ -748,7 +748,7 @@ void signTx_handleRequiredSigner_ui_runStep() ); #elif defined(HAVE_NBGL) char encodedStr[BECH32_STRING_SIZE_MAX] = {0}; - ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "req_signer_vfk", BODY_CTX->stageData.requiredSigner.keyHash, SIZEOF(BODY_CTX->stageData.requiredSigner.keyHash)); + ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "req_signer_vkh", BODY_CTX->stageData.requiredSigner.keyHash, SIZEOF(BODY_CTX->stageData.requiredSigner.keyHash)); fill_and_display_if_required("Required signer", encodedStr, this_fn, respond_with_user_reject); #endif // HAVE_BAGL break; diff --git a/src/uiScreens_nbgl.c b/src/uiScreens_nbgl.c index e11ca73d..88fa28fe 100644 --- a/src/uiScreens_nbgl.c +++ b/src/uiScreens_nbgl.c @@ -165,7 +165,7 @@ void ui_getStakingKeyScreen( ); } -void ui_getAccountScreeen( +void ui_getAccountScreen( char* line1, const size_t line1Size, char* line2, diff --git a/src/uiScreens_nbgl.h b/src/uiScreens_nbgl.h index a11316f9..b7424145 100644 --- a/src/uiScreens_nbgl.h +++ b/src/uiScreens_nbgl.h @@ -55,7 +55,7 @@ void ui_getAddressScreen( ); __noinline_due_to_stack__ -void ui_getAccountScreeen( +void ui_getAccountScreen( char* line1, const size_t line1Size, char* line2, From 094ad87fe1715428aefc06cbc4531593c8c64a5a Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Wed, 26 Apr 2023 01:18:38 +0200 Subject: [PATCH 053/105] fix: replace staking with stake in user msgs --- CHANGELOG.md | 2 +- doc/ins_sign_cip36_registration.md | 8 ++++---- doc/ins_sign_stake_pool_registration.md | 10 +++++----- doc/ins_sign_tx.md | 4 ++-- src/addressUtilsShelley.c | 14 +++++++------- src/bip44.c | 6 +++--- src/securityPolicy.c | 6 +++--- src/signTxCVoteRegistration.c | 2 +- src/signTxCVoteRegistration.h | 4 ++-- src/signTxCVoteRegistration_ui.c | 2 +- src/signTxCVoteRegistration_ui.h | 2 +- src/signTx_ui.c | 20 ++++++++++---------- src/txHashBuilder.c | 2 +- src/uiScreens_bagl.c | 12 ++++++------ src/uiScreens_nbgl.c | 10 +++++----- 15 files changed, 52 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c5a28b8..2ec353f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -205,7 +205,7 @@ d- Support bulk public key export: https://github.com/LedgerHQ/app-cardano/pull/ ### Fixed -- Serialize reward address instead of staking key into the withdrawals within the transaction body: https://github.com/LedgerHQ/app-cardano/pull/2 +- Serialize reward address instead of stake key into the withdrawals within the transaction body: https://github.com/LedgerHQ/app-cardano/pull/2 diff --git a/doc/ins_sign_cip36_registration.md b/doc/ins_sign_cip36_registration.md index 9fe21c43..9a3db321 100644 --- a/doc/ins_sign_cip36_registration.md +++ b/doc/ins_sign_cip36_registration.md @@ -2,7 +2,7 @@ ## Description -Cardano uses a sidechain for voting (initially used only for Catalyst, but CIP-36 allows other voting purposes). One needs to "register" to participate on this sidechain by submitting a registration transaction on the Cardano blockchain. This is done by submitting a transaction with specific auxiliary data attached to the transaction body. These auxiliary data contain a signature by user's staking key, hence serialization of the it by Ledger is required which after confirming by the user returns that signature for the client software to be able to assemble the full serialized transaction. +Cardano uses a sidechain for voting (initially used only for Catalyst, but CIP-36 allows other voting purposes). One needs to "register" to participate on this sidechain by submitting a registration transaction on the Cardano blockchain. This is done by submitting a transaction with specific auxiliary data attached to the transaction body. These auxiliary data contain a signature by user's stake key, hence serialization of the it by Ledger is required which after confirming by the user returns that signature for the client software to be able to assemble the full serialized transaction. For more details about voting registration see [CIP-0036](https://cips.cardano.org/cips/cip36/). @@ -64,7 +64,7 @@ P2 = `0x37` --- -**Staking key** +**Stake key** P2 = `0x31` @@ -72,7 +72,7 @@ P2 = `0x31` |Field| Length | Comments| |-----|--------|---------| -|staking key path | variable | BIP44 path. See [GetExtPubKey call](ins_get_extended_public_key.md) for a format example | +|stake key path | variable | BIP44 path. See [GetExtPubKey call](ins_get_extended_public_key.md) for a format example | --- @@ -140,6 +140,6 @@ Data must be empty. |Field|Length| Comments| |-----|-----|-----| | Auxiliary data hash | 32 | Hash of the registration auxiliary data| -| Signature |64| Voting registration signature by the staking key that has been supplied| +| Signature |64| Voting registration signature by the stake key that has been supplied| Note: voting registration auxiliary data is serialized in the [Mary-era format](https://github.com/input-output-hk/cardano-ledger-specs/blob/dcdbc38eb9caea16485827bd095d5adcdcca0aba/shelley-ma/shelley-ma-test/cddl-files/shelley-ma.cddl#L214), where the array of auxiliary scripts is fixed to an empty array. diff --git a/doc/ins_sign_stake_pool_registration.md b/doc/ins_sign_stake_pool_registration.md index 1c8f73ce..70106a6e 100644 --- a/doc/ins_sign_stake_pool_registration.md +++ b/doc/ins_sign_stake_pool_registration.md @@ -19,7 +19,7 @@ The key derivation scheme for pool cold keys used by a pool operator is describe - Pool id must be given by cold key derivation path. -- Pool owners must be given by hash (of the staking key). +- Pool owners must be given by hash (of the stake key). ## Signing mode for pool owner @@ -27,7 +27,7 @@ The key derivation scheme for pool cold keys used by a pool operator is describe - Transaction outputs must be given by addresses (not address params) and are not shown to the user (because he is not funding the transaction). The fee is not shown either. -- Only a single witness is allowed (the key derivation path is the standard staking key path of the owner). +- Only a single witness is allowed (the key derivation path is the standard stake key path of the owner). - It is necessary to include exactly one pool owner given by path in the certificate; all the other owners must be given by their respective key hashes. @@ -113,7 +113,7 @@ P2 = `0x34` |Field| Length | Comments| |-----|--------|---------| |key reference type | 1 | `KEY_REFERENCE_PATH=0x01` | -|staking key path | variable | BIP44 path. See [GetExtPubKey call](ins_get_public_keys.md) for a format example | +|stake key path | variable | BIP44 path. See [GetExtPubKey call](ins_get_public_keys.md) for a format example | |Field| Length | Comments| |-----|--------|---------| @@ -129,12 +129,12 @@ P2 = `0x35` |Field| Length | Comments| |-----|--------|---------| |key reference type | 1 | `KEY_REFERENCE_PATH=0x01` | -|staking key path | variable | BIP44 path. See [GetExtPubKey call](ins_get_public_keys.md) for a format example | +|stake key path | variable | BIP44 path. See [GetExtPubKey call](ins_get_public_keys.md) for a format example | |Field| Length | Comments| |-----|--------|---------| |key reference type | 1 | `KEY_REFERENCE_HASH=0x02` | -|staking key hash | 28 | | +|stake key hash | 28 | | --- diff --git a/doc/ins_sign_tx.md b/doc/ins_sign_tx.md index bbaafa4b..e8e6aeda 100644 --- a/doc/ins_sign_tx.md +++ b/doc/ins_sign_tx.md @@ -13,7 +13,7 @@ Due to Ledger constraints and potential security implications (parsing errors), **SignTx Limitations** - Output address size is limited to 128 bytes (single APDU). (Note: IOHK is fine with address size limit of 100 bytes) -- Addresses that are not shown to the user are base addresses with spending path `m/1852'/1815'/account'/{0,1}/changeIndex` and the standard staking key `m/1852'/1815'/account'/2/0`, where values of `account` and `changeIndex` are limited (for now, `0 <= account <= 100` and `0 <= changeIndex <= 1 000 000`). This makes it feasible to brute-force all change addresses in case an attacker manages to modify change address(es). (As the user does not confirm change addresses, it is relatively easy to perform MITM attack). +- Addresses that are not shown to the user are base addresses with spending path `m/1852'/1815'/account'/{0,1}/changeIndex` and the standard stake key `m/1852'/1815'/account'/2/0`, where values of `account` and `changeIndex` are limited (for now, `0 <= account <= 100` and `0 <= changeIndex <= 1 000 000`). This makes it feasible to brute-force all change addresses in case an attacker manages to modify change address(es). (As the user does not confirm change addresses, it is relatively easy to perform MITM attack). - Only transactions with at least one input will be signed (this provides protection against certificate replays and transaction replays on different networks). **Communication protocol non-goals:** @@ -277,7 +277,7 @@ This only describes the initial certificate message. All the data for this certi |Field| Length | Comments| |-----|--------|---------| |Output type| 1 | `CERTIFICATE_TYPE_STAKE_POOL_RETIREMENT=0x04`| -|Staking key path| variable | BIP44 path. See [GetExtPubKey call](ins_get_public_keys.md) for a format example | +|Stake key path| variable | BIP44 path. See [GetExtPubKey call](ins_get_public_keys.md) for a format example | |Pool key hash| 28 | Hash of staking pool public key| ### Reward withdrawal diff --git a/src/addressUtilsShelley.c b/src/addressUtilsShelley.c index 688c2c54..7740708e 100644 --- a/src/addressUtilsShelley.c +++ b/src/addressUtilsShelley.c @@ -218,8 +218,8 @@ static size_t deriveAddress_base(const addressParams_t* addressParams, uint8_t* ASSERT(false); } - STATIC_ASSERT(SIZEOF(addressParams->stakingKeyHash) == ADDRESS_KEY_HASH_LENGTH, "bad staking key hash size"); - STATIC_ASSERT(SIZEOF(addressParams->stakingScriptHash) == SCRIPT_HASH_LENGTH, "bad staking script hash size"); + STATIC_ASSERT(SIZEOF(addressParams->stakingKeyHash) == ADDRESS_KEY_HASH_LENGTH, "bad stake key hash size"); + STATIC_ASSERT(SIZEOF(addressParams->stakingScriptHash) == SCRIPT_HASH_LENGTH, "bad stake script hash size"); switch (addressParams->stakingDataSource) { case STAKING_KEY_PATH: { view_appendAddressPublicKeyHash(&out, &addressParams->stakingKeyPath); @@ -370,7 +370,7 @@ static size_t deriveAddress_reward( { if (addressType == REWARD_KEY) { const bip44_path_t* stakingKeyPath = &addressParams->stakingKeyPath; - // staking key path expected (corresponds to reward account) + // stake key path expected (corresponds to reward account) BIP44_PRINTF(stakingKeyPath); PRINTF("\n"); ASSERT(bip44_isOrdinaryStakingKeyPath(stakingKeyPath)); @@ -542,7 +542,7 @@ size_t humanReadableAddress(const uint8_t* address, size_t addressSize, char* ou * if STAKING_KEY_PATH: * staking public key derivation path (1B for length + [0-10] x 4B) * if STAKING_KEY_HASH: - * staking key hash 28B + * stake key hash 28B * if BLOCKCHAIN_POINTER: * certificate blockchain pointer 3 x 4B * @@ -617,7 +617,7 @@ void view_parseAddressParams(read_view_t* view, addressParams_t* params) case STAKING_KEY_HASH: { STATIC_ASSERT(SIZEOF(params->stakingKeyHash) == ADDRESS_KEY_HASH_LENGTH, "Wrong address key hash length"); view_parseBuffer(params->stakingKeyHash, view, ADDRESS_KEY_HASH_LENGTH); - TRACE("Staking key hash: "); + TRACE("Stake key hash: "); TRACE_BUFFER(params->stakingKeyHash, SIZEOF(params->stakingKeyHash)); break; } @@ -625,7 +625,7 @@ void view_parseAddressParams(read_view_t* view, addressParams_t* params) case STAKING_SCRIPT_HASH: { STATIC_ASSERT(SIZEOF(params->stakingScriptHash) == SCRIPT_HASH_LENGTH, "Wrong script hash length"); view_parseBuffer(params->stakingScriptHash, view, SCRIPT_HASH_LENGTH); - TRACE("Staking script hash: "); + TRACE("Stake script hash: "); TRACE_BUFFER(params->stakingScriptHash, SIZEOF(params->stakingScriptHash)); break; } @@ -634,7 +634,7 @@ void view_parseAddressParams(read_view_t* view, addressParams_t* params) params->stakingKeyBlockchainPointer.blockIndex = parse_u4be(view); params->stakingKeyBlockchainPointer.txIndex = parse_u4be(view); params->stakingKeyBlockchainPointer.certificateIndex = parse_u4be(view); - TRACE("Staking pointer: [%d, %d, %d]\n", + TRACE("Stake key pointer: [%d, %d, %d]\n", params->stakingKeyBlockchainPointer.blockIndex, params->stakingKeyBlockchainPointer.txIndex, params->stakingKeyBlockchainPointer.certificateIndex diff --git a/src/bip44.c b/src/bip44.c index 0907eb14..a65e2b96 100644 --- a/src/bip44.c +++ b/src/bip44.c @@ -218,7 +218,7 @@ static bool bip44_containsMoreThanAddress(const bip44_path_t* pathSpec) return (pathSpec->length > BIP44_I_ADDRESS + 1); } -// staking keys (one per account, should end with /2/0 after account) +// stake keys (one per account, should end with /2/0 after account) bool bip44_isOrdinaryStakingKeyPath(const bip44_path_t* pathSpec) { #define CHECK(cond) if (!(cond)) return false @@ -232,7 +232,7 @@ bool bip44_isOrdinaryStakingKeyPath(const bip44_path_t* pathSpec) #undef CHECK } -// multisig staking keys +// multisig stake keys bool bip44_isMultisigStakingKeyPath(const bip44_path_t* pathSpec) { #define CHECK(cond) if (!(cond)) return false @@ -485,7 +485,7 @@ bool bip44_isPathReasonable(const bip44_path_t* pathSpec) case PATH_ORDINARY_STAKING_KEY: case PATH_MULTISIG_STAKING_KEY: // we are checking the 5th item too (to avoid breaking this code - // if more than 1 staking key per account is allowed in the future) + // if more than 1 stake key per account is allowed in the future) return bip44_hasReasonableAccount(pathSpec) && bip44_hasReasonableAddress(pathSpec); case PATH_MINT_KEY: diff --git a/src/securityPolicy.c b/src/securityPolicy.c index a7cfa4bc..91ec902c 100644 --- a/src/securityPolicy.c +++ b/src/securityPolicy.c @@ -9,7 +9,7 @@ // helper functions -// staking key path has the same account as the spending key path +// stake key path has the same account as the spending key path static inline bool is_standard_base_address(const addressParams_t* addressParams) { ASSERT(isValidAddressParams(addressParams)); @@ -373,7 +373,7 @@ security_policy_t policyForSignTxInit( // witnesses for owners and withdrawals are the same // we forbid withdrawals so that users cannot be tricked into witnessing - // something unintentionally (e.g. an owner given by the staking key hash) + // something unintentionally (e.g. an owner given by the stake key hash) DENY_UNLESS(numWithdrawals == 0); // mint must not be combined with pool registration certificates @@ -1003,7 +1003,7 @@ security_policy_t policyForSignTxCertificate( DENY(); // should not be reached } -// for certificates concerning staking keys and stake delegation +// for certificates concerning stake keys and stake delegation security_policy_t policyForSignTxCertificateStaking( sign_tx_signingmode_t txSigningMode, const certificate_type_t certificateType, diff --git a/src/signTxCVoteRegistration.c b/src/signTxCVoteRegistration.c index a36e0f6d..63d288b9 100644 --- a/src/signTxCVoteRegistration.c +++ b/src/signTxCVoteRegistration.c @@ -370,7 +370,7 @@ static void signTxCVoteRegistration_handleDelegationAPDU(const uint8_t* wireData signTxCVoteRegistration_handleDelegation_ui_runStep(); } -// ============================== STAKING KEY ============================== +// ============================== STAKE KEY ============================== __noinline_due_to_stack__ static void signTxCVoteRegistration_handleStakingKeyAPDU(const uint8_t* wireDataBuffer, size_t wireDataSize) diff --git a/src/signTxCVoteRegistration.h b/src/signTxCVoteRegistration.h index 300ea65b..e4143dde 100644 --- a/src/signTxCVoteRegistration.h +++ b/src/signTxCVoteRegistration.h @@ -37,8 +37,8 @@ typedef struct { uint16_t numDelegations; // if 0, only a single key expected, no delegations uint16_t currentDelegation; /* - * Staking key path kept outside of stateData to produce the CIP-36 voting registration - * signature at the end of the flow without re-requesting the staking key path + * Stake key path kept outside of stateData to produce the CIP-36 voting registration + * signature at the end of the flow without re-requesting the stake key path * (with the undesired side-effect of allowing signing with a different key than included * in the registration payload) */ diff --git a/src/signTxCVoteRegistration_ui.c b/src/signTxCVoteRegistration_ui.c index 49f33fc4..8fea4b9e 100644 --- a/src/signTxCVoteRegistration_ui.c +++ b/src/signTxCVoteRegistration_ui.c @@ -144,7 +144,7 @@ void signTxCVoteRegistration_handleDelegation_ui_runStep() UI_STEP_END(HANDLE_DELEGATION_STEP_INVALID); } -// ============================== STAKING KEY ============================== +// ============================== STAKE KEY ============================== #ifdef HAVE_NBGL static void signTxCVoteRegistration_handleStakingKey_ui_cb(void) diff --git a/src/signTxCVoteRegistration_ui.h b/src/signTxCVoteRegistration_ui.h index b71551c8..39040f55 100644 --- a/src/signTxCVoteRegistration_ui.h +++ b/src/signTxCVoteRegistration_ui.h @@ -30,7 +30,7 @@ enum { void signTxCVoteRegistration_handleDelegation_ui_runStep(); -// ============================== STAKING KEY ============================== +// ============================== STAKE KEY ============================== enum { HANDLE_STAKING_KEY_STEP_WARNING = 8400, diff --git a/src/signTx_ui.c b/src/signTx_ui.c index d5636f8b..67bb2d9d 100644 --- a/src/signTx_ui.c +++ b/src/signTx_ui.c @@ -366,12 +366,12 @@ void signTx_handleCertificate_ui_runStep() #ifdef HAVE_BAGL ui_displayPaginatedText( "Register", - "staking key", + "stake key", this_fn ); #elif defined(HAVE_NBGL) set_light_confirmation(true); - display_prompt("Register\nstaking key", "", this_fn, respond_with_user_reject); + display_prompt("Register\nstake key", "", this_fn, respond_with_user_reject); #endif // HAVE_BAGL break; @@ -379,12 +379,12 @@ void signTx_handleCertificate_ui_runStep() #ifdef HAVE_BAGL ui_displayPaginatedText( "Deregister", - "staking key", + "stake key", this_fn ); #elif defined(HAVE_NBGL) set_light_confirmation(true); - display_prompt("Deregister\nstaking key", "", this_fn, respond_with_user_reject); + display_prompt("Deregister\nstake key", "", this_fn, respond_with_user_reject); #endif // HAVE_BAGL break; @@ -414,7 +414,7 @@ void signTx_handleCertificate_ui_runStep() case STAKE_CREDENTIAL_KEY_PATH: #ifdef HAVE_BAGL ui_displayPathScreen( - "Staking key", + "Stake key", &BODY_CTX->stageData.certificate.stakeCredential.keyPath, this_fn ); @@ -422,14 +422,14 @@ void signTx_handleCertificate_ui_runStep() { char pathStr[BIP44_PATH_STRING_SIZE_MAX + 1] = {0}; ui_getPathScreen(pathStr, SIZEOF(pathStr), &BODY_CTX->stageData.certificate.stakeCredential.keyPath); - fill_and_display_if_required("Staking key", pathStr, this_fn, respond_with_user_reject); + fill_and_display_if_required("Stake key", pathStr, this_fn, respond_with_user_reject); } #endif // HAVE_BAGL break; case STAKE_CREDENTIAL_KEY_HASH: #ifdef HAVE_BAGL ui_displayBech32Screen( - "Staking key hash", + "Stake key hash", "stake_vkh", BODY_CTX->stageData.certificate.stakeCredential.keyHash, SIZEOF(BODY_CTX->stageData.certificate.stakeCredential.keyHash), @@ -439,14 +439,14 @@ void signTx_handleCertificate_ui_runStep() { char encodedStr[BECH32_STRING_SIZE_MAX] = {0}; ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "stake_vkh", BODY_CTX->stageData.certificate.stakeCredential.keyHash, SIZEOF(BODY_CTX->stageData.certificate.stakeCredential.keyHash)); - fill_and_display_if_required("Staking key hash", encodedStr, this_fn, respond_with_user_reject); + fill_and_display_if_required("Stake key hash", encodedStr, this_fn, respond_with_user_reject); } #endif // HAVE_BAGL break; case STAKE_CREDENTIAL_SCRIPT_HASH: #ifdef HAVE_BAGL ui_displayBech32Screen( - "Staking script hash", + "Stake script hash", "script", BODY_CTX->stageData.certificate.stakeCredential.scriptHash, SIZEOF(BODY_CTX->stageData.certificate.stakeCredential.scriptHash), @@ -456,7 +456,7 @@ void signTx_handleCertificate_ui_runStep() { char encodedStr[BECH32_STRING_SIZE_MAX] = {0}; ui_getBech32Screen(encodedStr, SIZEOF(encodedStr), "script", BODY_CTX->stageData.certificate.stakeCredential.scriptHash, SIZEOF(BODY_CTX->stageData.certificate.stakeCredential.scriptHash)); - fill_and_display_if_required("Staking script hash", encodedStr, this_fn, respond_with_user_reject); + fill_and_display_if_required("Stake script hash", encodedStr, this_fn, respond_with_user_reject); } #endif // HAVE_BAGL break; diff --git a/src/txHashBuilder.c b/src/txHashBuilder.c index 274b4fb1..8c50e1b5 100644 --- a/src/txHashBuilder.c +++ b/src/txHashBuilder.c @@ -764,7 +764,7 @@ static uint32_t getStakeCredentialSource(const stake_credential_type_t stakeCred } } -// staking key certificate registration or deregistration +// stake key certificate registration or deregistration void txHashBuilder_addCertificate_stakingHash( tx_hash_builder_t* builder, const certificate_type_t certificateType, diff --git a/src/uiScreens_bagl.c b/src/uiScreens_bagl.c index bdc8044f..34307ba3 100644 --- a/src/uiScreens_bagl.c +++ b/src/uiScreens_bagl.c @@ -213,7 +213,7 @@ void ui_displayStakingKeyScreen( bool showAccountDescription = bip44_isPathReasonable(stakingPath); _ui_displayAccountWithDescriptionScreen( - "Staking key", + "Stake key", stakingPath, showAccountDescription, callback @@ -249,7 +249,7 @@ void ui_displayAddressScreen( ); } -// display bech32-encoded reward account preceded by staking key derivation path (if given) +// display bech32-encoded reward account preceded by stake key derivation path (if given) static void _displayRewardAccountWithDescriptionScreen( const key_reference_type_t keyReferenceType, const bip44_path_t* path, @@ -398,10 +398,10 @@ void ui_displaySpendingInfoScreen( } } -static const char STAKING_HEADING_PATH[] = "Staking key path"; -static const char STAKING_HEADING_KEY_HASH[] = "Staking key hash"; -static const char STAKING_HEADING_SCRIPT_HASH[] = "Staking script hash"; -static const char STAKING_HEADING_POINTER[] = "Staking key pointer"; +static const char STAKING_HEADING_PATH[] = "Stake key path"; +static const char STAKING_HEADING_KEY_HASH[] = "Stake key hash"; +static const char STAKING_HEADING_SCRIPT_HASH[] = "Stake script hash"; +static const char STAKING_HEADING_POINTER[] = "Stake key pointer"; static const char STAKING_HEADING_WARNING[] = "WARNING:"; void ui_displayStakingInfoScreen( diff --git a/src/uiScreens_nbgl.c b/src/uiScreens_nbgl.c index 88fa28fe..4b9d493f 100644 --- a/src/uiScreens_nbgl.c +++ b/src/uiScreens_nbgl.c @@ -224,7 +224,7 @@ void ui_getAddressScreen( ASSERT(strlen(line) == length); } -// display bech32-encoded reward account preceded by staking key derivation path (if given) +// display bech32-encoded reward account preceded by stake key derivation path (if given) static void _getRewardAccountWithDescriptionScreen( char* line, const size_t lineSize, @@ -373,10 +373,10 @@ void ui_getSpendingInfoScreen( } } -static const char STAKING_HEADING_PATH[] = "Staking key path"; -static const char STAKING_HEADING_KEY_HASH[] = "Staking key hash"; -static const char STAKING_HEADING_SCRIPT_HASH[] = "Staking script hash"; -static const char STAKING_HEADING_POINTER[] = "Staking key pointer"; +static const char STAKING_HEADING_PATH[] = "Stake key path"; +static const char STAKING_HEADING_KEY_HASH[] = "Stake key hash"; +static const char STAKING_HEADING_SCRIPT_HASH[] = "Stake script hash"; +static const char STAKING_HEADING_POINTER[] = "Stake key pointer"; static const char STAKING_HEADING_WARNING[] = "WARNING:"; void ui_getStakingInfoScreen( From cbf2812de2a05ddefb6329f1cc19c11db1e83b46 Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Wed, 26 Apr 2023 01:29:02 +0200 Subject: [PATCH 054/105] fix: ui msgs for stake delegation --- src/signTxPoolRegistration_ui.c | 2 +- src/signTx_ui.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/signTxPoolRegistration_ui.c b/src/signTxPoolRegistration_ui.c index 09e0492a..04ece815 100644 --- a/src/signTxPoolRegistration_ui.c +++ b/src/signTxPoolRegistration_ui.c @@ -634,7 +634,7 @@ void handleNullMetadata_ui_runStep() #elif defined(HAVE_NBGL) fill_and_display_if_required( "Metadata", - "None: anymous pool", + "none (anonymous pool)", this_fn, respond_with_user_reject ); diff --git a/src/signTx_ui.c b/src/signTx_ui.c index 67bb2d9d..91e4685a 100644 --- a/src/signTx_ui.c +++ b/src/signTx_ui.c @@ -391,14 +391,14 @@ void signTx_handleCertificate_ui_runStep() case CERTIFICATE_TYPE_STAKE_DELEGATION: #ifdef HAVE_BAGL ui_displayBech32Screen( - "Delegate stake to", - "pool", + "Delegate stake", + "to pool", BODY_CTX->stageData.certificate.poolKeyHash, SIZEOF(BODY_CTX->stageData.certificate.poolKeyHash), this_fn ); #elif defined(HAVE_NBGL) set_light_confirmation(true); - display_prompt("Delegate staking\nconfirmation key", "", signTx_handleCertificate_ui_delegation_cb, respond_with_user_reject); + display_prompt("Delegate stake", "", signTx_handleCertificate_ui_delegation_cb, respond_with_user_reject); #endif // HAVE_BAGL break; From 763672fc5e3c009558570bb936cd5f7586299ced Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Wed, 26 Apr 2023 01:32:16 +0200 Subject: [PATCH 055/105] fix: ui msg for tx confirmation --- src/signTx_ui.c | 3 ++- src/uiScreens_nbgl.c | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/signTx_ui.c b/src/signTx_ui.c index 91e4685a..791f2254 100644 --- a/src/signTx_ui.c +++ b/src/signTx_ui.c @@ -832,7 +832,8 @@ void signTx_handleConfirm_ui_runStep() respond_with_user_reject ); #elif defined(HAVE_NBGL) - display_confirmation("Sign\ntransaction", "", "TRANSACTION\nSIGNED", "Transaction\nrejected", this_fn, respond_with_user_reject); + // we can't say that the tx is signed because the witnesses have not been processed yet + display_confirmation("Sign\ntransaction", "", "TRANSACTION\nCONFIRMED", "Transaction\nrejected", this_fn, respond_with_user_reject); #endif // HAVE_BAGL } UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { diff --git a/src/uiScreens_nbgl.c b/src/uiScreens_nbgl.c index 4b9d493f..2a2a22bf 100644 --- a/src/uiScreens_nbgl.c +++ b/src/uiScreens_nbgl.c @@ -25,7 +25,6 @@ void ui_getBech32Screen( ASSERT(bufferSize <= BECH32_BUFFER_SIZE_MAX); } - // rough upper bound on required size is used explicit_bzero(line, lineSize); { From c4280bdfdf4ccd32f714c84e582a5403b44aa8e4 Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Wed, 26 Apr 2023 01:45:02 +0200 Subject: [PATCH 056/105] fix: ui msg for outputs --- src/signTxOutput_ui.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/signTxOutput_ui.c b/src/signTxOutput_ui.c index a682a632..4ceb52e6 100644 --- a/src/signTxOutput_ui.c +++ b/src/signTxOutput_ui.c @@ -117,7 +117,11 @@ void signTx_handleOutput_addressParams_ui_runStep() ui_displayPaginatedText(subctx->ui_text1, subctx->ui_text2, this_fn); #elif defined(HAVE_NBGL) set_light_confirmation(true); - display_prompt("Change output", "", this_fn, respond_with_user_reject); + // the ui msg depends on whether we are processing ordinary or collateral output + char msg[100] = {0}; + snprintf(msg, SIZEOF(msg), "%s\n%s", subctx->ui_text1, subctx->ui_text2); + ASSERT(strlen(msg) + 1 < SIZEOF(msg)); + display_prompt(msg, "", this_fn, respond_with_user_reject); #endif // HAVE_BAGL } UI_STEP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_SPENDING_PATH) { @@ -161,7 +165,7 @@ void signTx_handleOutput_addressParams_ui_runStep() addressBuffer, addressSize ); - fill_and_display_if_required("Address", humanAddress, this_fn, respond_with_user_reject); + fill_and_display_if_required(subctx->ui_text3, humanAddress, this_fn, respond_with_user_reject); #endif // HAVE_BAGL } UI_STEP(HANDLE_OUTPUT_ADDRESS_PARAMS_STEP_DISPLAY_AMOUNT) { @@ -440,7 +444,11 @@ void signTxOutput_handleConfirm_ui_runStep() ); #elif defined(HAVE_NBGL) set_light_confirmation(true); - display_confirmation("Confirm output", "", "OUTPUT\nCONFIRMED", "Output\nrejected", this_fn, respond_with_user_reject); + // the ui msg depends on whether we are processing ordinary or collateral output + char msg[100] = {0}; + snprintf(msg, SIZEOF(msg), "%s\n%s", subctx->ui_text1, subctx->ui_text2); + ASSERT(strlen(msg) + 1 < SIZEOF(msg)); + display_confirmation(msg, "", "OUTPUT\nCONFIRMED", "Output\nrejected", this_fn, respond_with_user_reject); #endif // HAVE_BAGL } UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { From 832b3107e438f532284b6767d2d882c3069ed910 Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Wed, 26 Apr 2023 11:48:17 +0200 Subject: [PATCH 057/105] fix: add missing header --- src/assert.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/assert.c b/src/assert.c index 82caf643..2dba2362 100644 --- a/src/assert.c +++ b/src/assert.c @@ -1,6 +1,7 @@ #include "common.h" #include "assert.h" #include "uiHelpers.h" +#include "uiScreens_nbgl.h" // Note(ppershing): In DEBUG we need to keep going // because rendering on display takes multiple SEPROXYHAL From 73c7c07e0221da727082ea05272fb7fc599e77b9 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 12 May 2023 17:53:16 +0200 Subject: [PATCH 058/105] Misc: fix wordings --- src/getPublicKeys_ui.c | 2 +- src/signTxOutput_ui.c | 4 ++-- src/signTx_ui.c | 12 ++++++------ src/ui_menu_nbgl.c | 4 ++-- src/ui_nbgl.c | 14 +++++++------- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/getPublicKeys_ui.c b/src/getPublicKeys_ui.c index 8cbc8809..d38b43ee 100644 --- a/src/getPublicKeys_ui.c +++ b/src/getPublicKeys_ui.c @@ -134,7 +134,7 @@ void getPublicKeys_handleInit_ui_runStep() explicit_bzero(secondLine, SIZEOF(secondLine)); STATIC_ASSERT(sizeof(ctx->numPaths) <= sizeof(unsigned), "oversized type for %u"); STATIC_ASSERT(!IS_SIGNED(ctx->numPaths), "signed type for %u"); - snprintf(secondLine, SIZEOF(secondLine), "%u public keys?", ctx->numPaths); + snprintf(secondLine, SIZEOF(secondLine), "Allow the Cardano app to\nexport your %u public keys?", ctx->numPaths); // make sure all the information is displayed to the user ASSERT(strlen(secondLine) + 1 < SIZEOF(secondLine)); diff --git a/src/signTxOutput_ui.c b/src/signTxOutput_ui.c index 4ceb52e6..de75d286 100644 --- a/src/signTxOutput_ui.c +++ b/src/signTxOutput_ui.c @@ -62,7 +62,7 @@ void signTx_handleOutput_address_bytes_ui_runStep() subctx->stateData.destination.address.buffer, subctx->stateData.destination.address.size ); - fill_and_display_if_required("Send to address", humanAddress, this_fn, respond_with_user_reject); + fill_and_display_if_required("To", humanAddress, this_fn, respond_with_user_reject); #endif // HAVE_BAGL } UI_STEP(HANDLE_OUTPUT_ADDRESS_BYTES_STEP_WARNING_DATUM) { @@ -92,7 +92,7 @@ void signTx_handleOutput_address_bytes_ui_runStep() #elif defined(HAVE_NBGL) char adaAmountStr[50] = {0}; ui_getAdaAmountScreen(adaAmountStr, SIZEOF(adaAmountStr), subctx->stateData.adaAmount); - fill_and_display_if_required("Send", adaAmountStr, this_fn, respond_with_user_reject); + fill_and_display_if_required("Amount", adaAmountStr, this_fn, respond_with_user_reject); #endif // HAVE_BAGL } UI_STEP(HANDLE_OUTPUT_ADDRESS_BYTES_STEP_RESPOND) { diff --git a/src/signTx_ui.c b/src/signTx_ui.c index 791f2254..f00a303c 100644 --- a/src/signTx_ui.c +++ b/src/signTx_ui.c @@ -35,35 +35,35 @@ static const char* _newTxLine1(sign_tx_signingmode_t txSigningMode) #ifdef HAVE_BAGL return "New ordinary"; #elif defined(HAVE_NBGL) - return "New ordinary\ntransaction"; + return "Review transaction"; #endif // HAVE_BAGL case SIGN_TX_SIGNINGMODE_POOL_REGISTRATION_OWNER: #ifdef HAVE_BAGL return "New pool owner"; #elif defined(HAVE_NBGL) - return "New pool owner\ntransaction"; + return "Review pool owner\ntransaction"; #endif // HAVE_BAGL case SIGN_TX_SIGNINGMODE_POOL_REGISTRATION_OPERATOR: #ifdef HAVE_BAGL return "New pool operator"; #elif defined(HAVE_NBGL) - return "New pool operator\ntransaction"; + return "Review pool operator\ntransaction"; #endif // HAVE_BAGL case SIGN_TX_SIGNINGMODE_MULTISIG_TX: #ifdef HAVE_BAGL return "New multisig"; #elif defined(HAVE_NBGL) - return "New multisig\ntransaction"; + return "Review multisig\ntransaction"; #endif // HAVE_BAGL case SIGN_TX_SIGNINGMODE_PLUTUS_TX: #ifdef HAVE_BAGL return "New Plutus"; #elif defined(HAVE_NBGL) - return "New Plutus\ntransaction"; + return "Review Plutus\ntransaction"; #endif // HAVE_BAGL default: @@ -302,7 +302,7 @@ void signTx_handleFee_ui_runStep() #elif defined(HAVE_NBGL) char adaAmountStr[50] = {0}; ui_getAdaAmountScreen(adaAmountStr, SIZEOF(adaAmountStr), BODY_CTX->stageData.fee); - fill_and_display_if_required("Transaction fee", adaAmountStr, this_fn, respond_with_user_reject); + fill_and_display_if_required("Fees", adaAmountStr, this_fn, respond_with_user_reject); #endif // HAVE_BAGL } UI_STEP(HANDLE_FEE_STEP_RESPOND) { diff --git a/src/ui_menu_nbgl.c b/src/ui_menu_nbgl.c index 0eee71f3..7c06742b 100644 --- a/src/ui_menu_nbgl.c +++ b/src/ui_menu_nbgl.c @@ -50,8 +50,8 @@ static void exit(void) static bool settings_navigation_callback(uint8_t page, nbgl_pageContent_t* content) { if (page == 0) { - switches[0].text = "Enable expert mode"; - switches[0].subText = "Select application mode"; + switches[0].text = "Expert mode"; + switches[0].subText = "Enable expert mode"; switches[0].token = SWITCH_APP_MODE_TOKEN; switches[0].tuneId = TUNE_TAP_CASUAL; switches[0].initState = app_mode_expert(); diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index f0798c79..8ab019a7 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -171,7 +171,7 @@ static void _display_confirmation(void) .progressIndicator = true, .navWithTap.backButton = false, .navWithTap.nextPageText = NULL, - .navWithTap.quitText = "Reject", + .navWithTap.quitText = "Reject transaction", .quitToken = CANCEL_PROMPT_TOKEN, .tuneId = TUNE_TAP_CASUAL }; @@ -180,7 +180,7 @@ static void _display_confirmation(void) .type = INFO_LONG_PRESS, .infoLongPress.icon = &C_cardano_64, .infoLongPress.text = uiContext.pageText[0], - .infoLongPress.longPressText = "Hold to approve", + .infoLongPress.longPressText = "Hold to sign", .infoLongPress.longPressToken = CONFIRMATION_STATUS_TOKEN, .infoLongPress.tuneId = TUNE_TAP_NEXT }; @@ -207,7 +207,7 @@ static void _display_light_confirmation(void) TRACE("_light_confirmation"); nbgl_useCaseChoice(&C_cardano_64, uiContext.pageText[0], "", - "Confirm", "Cancel", light_confirm_callback); + "Confirm", "Reject Transaction", light_confirm_callback); #ifdef HEADLESS trigger_callback(uiContext.approvedCallback); @@ -220,7 +220,7 @@ static void display_cancel(void) display_cancel_status(); } else { nbgl_useCaseConfirm("Reject ?", NULL, "Yes, Reject", - "Go back", display_cancel_status); + "Go back to transaction", display_cancel_status); } } @@ -262,7 +262,7 @@ static void _display_page(void) .navWithTap.backButton = false, .navWithTap.nextPageText = "Tap to continue", .navWithTap.nextPageToken = ACCEPT_PAGE_TOKEN, - .navWithTap.quitText = "Cancel", + .navWithTap.quitText = "Reject transaction", .quitToken = CANCEL_PROMPT_TOKEN, .tuneId = TUNE_TAP_CASUAL }; @@ -287,8 +287,8 @@ static void _display_prompt(void) TRACE("_prompt"); nbgl_useCaseReviewStart(&C_cardano_64, uiContext.pageText[0], - uiContext.pageText[1], "Reject if not sure", uiContext.approvedCallback, &display_cancel); + uiContext.pageText[1], "Reject transaction", #ifdef HEADLESS nbgl_refresh(); trigger_callback(uiContext.approvedCallback); @@ -338,7 +338,7 @@ static void display_address_callback(void) uiContext.pairList.pairs = tagValues; uiContext.confirmedStatus = "ADDRESS\nVERIFIED"; - uiContext.rejectedStatus = "Address rejected"; + uiContext.rejectedStatus = "Address verification\ncancelled"; for (uint8_t i = 0; i < uiContext.currentElementCount; i++) { if (strcmp(uiContext.tagTitle[i], "Address")) { From a08fe582b90cbc65d06011453c36c86587d1592b Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 12 May 2023 17:53:46 +0200 Subject: [PATCH 059/105] nbgl: fix element line count --- src/ui_nbgl.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index 8ab019a7..5cbde1a8 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -22,7 +22,6 @@ #include "uiScreens_nbgl.h" #define MAX_LINE_PER_PAGE_COUNT NB_MAX_LINES_IN_REVIEW -#define MAX_TAG_CONTENT_CHAR_PER_LINE 18 #define MAX_TAG_TITLE_LINE_LENGTH 30 #define MAX_TAG_CONTENT_LENGTH 200 #define MAX_TEXT_STRING 50 @@ -76,9 +75,14 @@ static void release_context(void) } } -static inline uint8_t get_element_line_count(const char* line) +static inline uint16_t get_element_line_count(const char* line) { - return strlen(line) / MAX_TAG_CONTENT_CHAR_PER_LINE + 2; + uint16_t nbLines = nbgl_getTextNbLinesInWidth(BAGL_FONT_INTER_MEDIUM_32px, + line, + SCREEN_WIDTH - 2 * BORDER_MARGIN, + false); + + return nbLines + 1; // For title } static void set_callbacks(callback_t approvedCallback, callback_t rejectedCallback) From 07b565210ba49948a054e44b0869f4038dce13f7 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 12 May 2023 17:54:30 +0200 Subject: [PATCH 060/105] nbgl: add static callback to always draw processing screen --- src/ui_nbgl.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index 5cbde1a8..0d7e3a20 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -85,6 +85,12 @@ static inline uint16_t get_element_line_count(const char* line) return nbLines + 1; // For title } +static void ui_callback(void) +{ + nbgl_useCaseSpinner("Processing"); + uiContext.approvedCallback(); +} + static void set_callbacks(callback_t approvedCallback, callback_t rejectedCallback) { uiContext.approvedCallback = approvedCallback; @@ -150,7 +156,7 @@ static void display_callback(int token, unsigned char index) callback = uiContext.pendingDisplayPageFn; uiContext.pendingDisplayPageFn = NULL; } else { - callback = uiContext.approvedCallback; + callback = ui_callback; } callback(); break; @@ -193,7 +199,7 @@ static void _display_confirmation(void) #ifdef HEADLESS nbgl_refresh(); - trigger_callback(uiContext.approvedCallback); + trigger_callback(ui_callback); #endif } @@ -214,7 +220,7 @@ static void _display_light_confirmation(void) "Confirm", "Reject Transaction", light_confirm_callback); #ifdef HEADLESS - trigger_callback(uiContext.approvedCallback); + trigger_callback(ui_callback); #endif } @@ -282,7 +288,7 @@ static void _display_page(void) #ifdef HEADLESS nbgl_refresh(); - trigger_callback(uiContext.approvedCallback); + trigger_callback(ui_callback); #endif } @@ -291,11 +297,11 @@ static void _display_prompt(void) TRACE("_prompt"); nbgl_useCaseReviewStart(&C_cardano_64, uiContext.pageText[0], - uiContext.approvedCallback, &display_cancel); uiContext.pageText[1], "Reject transaction", + ui_callback, &display_cancel); #ifdef HEADLESS nbgl_refresh(); - trigger_callback(uiContext.approvedCallback); + trigger_callback(ui_callback); #endif } @@ -305,10 +311,10 @@ static void _display_warning(void) nbgl_useCaseReviewStart(&C_warning64px, "WARNING", uiContext.pageText[0], "Reject if not sure", - uiContext.approvedCallback, &display_cancel); + ui_callback, &display_cancel); #ifdef HEADLESS nbgl_refresh(); - trigger_callback(uiContext.approvedCallback); + trigger_callback(ui_callback); #endif } @@ -325,7 +331,7 @@ static void confirmation_status_callback(void) static void display_confirmation_status(void) { if (uiContext.approvedCallback) { - uiContext.approvedCallback(); + ui_callback(); } if (!uiContext.no_approved_status) { From d226eb2af7ba9ead9a2a5677ff4f6303466e33f9 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 12 May 2023 17:50:52 +0200 Subject: [PATCH 061/105] nbgl: use ticker event to trigger callback --- src/io.c | 24 ++++++++++++++++++++++++ src/io.h | 6 ++++++ src/ui_nbgl.c | 30 ++---------------------------- 3 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/io.c b/src/io.c index f8b9eac5..5f243e46 100644 --- a/src/io.c +++ b/src/io.c @@ -1,8 +1,24 @@ #include "io.h" #include "common.h" +#include "ui.h" io_state_t io_state; +#ifdef HAVE_NBGL +static callback_t app_callback; +static callback_t _callback; + +void set_app_callback(callback_t cb) +{ + app_callback = cb; +} + +void reset_app_callback(void) +{ + app_callback = NULL; +} +#endif + #if defined(TARGET_NANOS) static timeout_callback_fn_t* timeout_cb; @@ -118,6 +134,14 @@ unsigned char io_event(unsigned char channel MARK_UNUSED) TRACE("timer"); HANDLE_UX_TICKER_EVENT(UX_ALLOWED); }); + #ifdef HAVE_NBGL + if (app_callback) { + _callback = app_callback; + reset_app_callback(); + _callback(); + } + #endif + break; default: diff --git a/src/io.h b/src/io.h index fa9aecb4..13d23f19 100644 --- a/src/io.h +++ b/src/io.h @@ -5,6 +5,7 @@ #include #include #include +#include "ui.h" enum { P1_UNUSED = 0, @@ -62,4 +63,9 @@ void nanos_clear_timer(); // does not actually work anymore in Nano X #endif +#ifdef HAVE_NBGL +void set_app_callback(callback_t cb); +void reset_app_callback(void); +#endif // HAVE_NBGL + #endif // H_CARDANO_APP_IO diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index 0d7e3a20..1be27ba6 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -370,34 +370,8 @@ static void display_address_callback(void) static void trigger_callback(callback_t userAcceptCallback) { - // Hack to trigger a callback from NBGL while leaving the screen untouched - nbgl_layoutDescription_t layoutDescription; - nbgl_layout_t* layout = NULL; - nbgl_layoutCenteredInfo_t centeredInfo = { - .text1 = NULL, - .text2 = NULL, - .text3 = NULL, - .style = 0, - .icon = NULL, - .offsetY = 0 - }; - - release_context(); - - layoutDescription.modal = false; - layoutDescription.withLeftBorder = true; - - layoutDescription.onActionCallback = NULL; - layoutDescription.tapActionText = ""; - layoutDescription.tapActionToken = 0; - layoutDescription.tapTuneId = TUNE_TAP_CASUAL; - - layoutDescription.ticker.tickerCallback = userAcceptCallback; - layoutDescription.ticker.tickerIntervale = 0; - layoutDescription.ticker.tickerValue = 100; - pageContext = nbgl_layoutGet(&layoutDescription); - - nbgl_layoutAddCenteredInfo(layout, ¢eredInfo); + set_app_callback(userAcceptCallback); + nbgl_useCaseSpinner("Processing"); } static void handle_pending_element(void) From 3cd358c3a984c4d102e0bfd79c8ba4f56cb39c98 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 12 May 2023 18:18:40 +0200 Subject: [PATCH 062/105] nbgl: display "Export public key" as info instead of prompt --- src/getPublicKeys_ui.c | 5 ++--- src/ui_nbgl.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/getPublicKeys_ui.c b/src/getPublicKeys_ui.c index d38b43ee..a083693e 100644 --- a/src/getPublicKeys_ui.c +++ b/src/getPublicKeys_ui.c @@ -147,9 +147,8 @@ void getPublicKeys_handleInit_ui_runStep() ); #elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_prompt( - "Review export", + display_choice( + "Export Public key ?", secondLine, this_fn, respond_with_user_reject diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index 1be27ba6..605edb0d 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -318,6 +318,28 @@ static void _display_warning(void) #endif } +static void display_choice_callback(bool choice) +{ + if (choice) { + ui_callback(); + } else { + display_cancel(); + } +} + +static void _display_choice(void) +{ + TRACE("_choice"); + + nbgl_useCaseChoice(&C_round_warning_64px, uiContext.pageText[0], + uiContext.pageText[1], "Allow", "Don't Allow", + display_choice_callback); + #ifdef HEADLESS + nbgl_refresh(); + trigger_callback(ui_callback); + #endif +} + static void confirmation_status_callback(void) { if (uiContext.confirmedStatus) { @@ -506,6 +528,17 @@ void display_warning(const char* text, callback_t userAcceptCallback, _display_page_or_call_function(&_display_warning); } +void display_choice(const char* text1, const char* text2, callback_t userAcceptCallback, + callback_t userRejectCallback) +{ + TRACE("Displaying choice"); + + set_callbacks(userAcceptCallback, userRejectCallback); + strncpy(uiContext.pageText[0], text1, MAX_TEXT_STRING); + strncpy(uiContext.pageText[1], text2, MAX_TEXT_STRING); + _display_page_or_call_function(&_display_choice); +} + void display_address(callback_t userAcceptCallback, callback_t userRejectCallback) { TRACE("Displaying Address"); From 1b3309f46471c4d771bf499eabbd0653e040c67c Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 12 May 2023 18:36:00 +0200 Subject: [PATCH 063/105] nbgl: improve status display --- src/signTx.c | 1 + src/signTx_ui.c | 12 +++++++++--- src/signTx_ui.h | 1 + src/ui.h | 2 ++ src/ui_nbgl.c | 7 ++++++- 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/signTx.c b/src/signTx.c index 456245ab..f26bec2d 100644 --- a/src/signTx.c +++ b/src/signTx.c @@ -275,6 +275,7 @@ void tx_advanceStage() case SIGN_STAGE_WITNESSES: ctx->stage = SIGN_STAGE_NONE; ui_idle(); // we are done with this tx + endTxStatus(); break; case SIGN_STAGE_NONE: diff --git a/src/signTx_ui.c b/src/signTx_ui.c index f00a303c..149989a1 100644 --- a/src/signTx_ui.c +++ b/src/signTx_ui.c @@ -832,8 +832,7 @@ void signTx_handleConfirm_ui_runStep() respond_with_user_reject ); #elif defined(HAVE_NBGL) - // we can't say that the tx is signed because the witnesses have not been processed yet - display_confirmation("Sign\ntransaction", "", "TRANSACTION\nCONFIRMED", "Transaction\nrejected", this_fn, respond_with_user_reject); + display_confirmation("Sign\ntransaction", "", NULL, "Transaction\nrejected", this_fn, respond_with_user_reject); #endif // HAVE_BAGL } UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { @@ -895,7 +894,7 @@ void signTx_handleWitness_ui_runStep() _wipeWitnessSignature ); #elif defined(HAVE_NBGL) - display_confirmation("Sign using witness", "", "SIGNATURE\nCONFIRMED", "Signature\nrejected", this_fn, _wipeWitnessSignature); + display_confirmation("Sign using witness", "", NULL, "Signature\nrejected", this_fn, _wipeWitnessSignature); #endif // HAVE_BAGL } UI_STEP(HANDLE_WITNESS_STEP_RESPOND) { @@ -913,3 +912,10 @@ void signTx_handleWitness_ui_runStep() } UI_STEP_END(HANDLE_WITNESS_STEP_INVALID); } + +void endTxStatus(void) +{ + #ifdef HAVE_NBGL + display_status("TRANSACTION\nCONFIRMED"); + #endif // HAVE_NBGL +} diff --git a/src/signTx_ui.h b/src/signTx_ui.h index 11982f34..775517d0 100644 --- a/src/signTx_ui.h +++ b/src/signTx_ui.h @@ -160,4 +160,5 @@ enum { }; void signTx_handleWitness_ui_runStep(); +void endTxStatus(void); #endif // H_CARDANO_APP_SIGN_TX_UI diff --git a/src/ui.h b/src/ui.h index 2dffc3ed..0a78cf6e 100644 --- a/src/ui.h +++ b/src/ui.h @@ -17,6 +17,8 @@ void display_confirmation_no_approved_status(const char* text1, const char* text void display_page(callback_t user_accept_cb, callback_t user_reject_cb); void display_prompt(const char* text1, const char* text2, callback_t user_accept_cb, callback_t user_reject_cb); void display_warning(const char* text, callback_t user_accept_cb, callback_t user_reject_cb); +void display_choice(const char* text1, const char* text2, callback_t userAcceptCallback, callback_t userRejectCallback); +void display_status(const char* text); void ui_idle(void); void ui_idle_flow(void); void display_cancel_message(void); diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index 605edb0d..d5806aa2 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -345,7 +345,7 @@ static void confirmation_status_callback(void) if (uiContext.confirmedStatus) { nbgl_useCaseStatus(uiContext.confirmedStatus, true, ui_idle_flow); } else { - nbgl_useCaseStatus("ACTION\nCONFIRMED", true, ui_idle_flow); + nbgl_useCaseSpinner("Processing"); } } @@ -542,6 +542,7 @@ void display_choice(const char* text1, const char* text2, callback_t userAcceptC void display_address(callback_t userAcceptCallback, callback_t userRejectCallback) { TRACE("Displaying Address"); + uiContext.rejectedStatus = "Address verification\ncancelled"; set_callbacks(userAcceptCallback, userRejectCallback); nbgl_useCaseReviewStart(&C_cardano_64, "Verify Cardano\naddress", @@ -561,4 +562,8 @@ void display_error(void) nbgl_useCaseStatus("An error has occurred", false, ui_idle_flow); } +void display_status(const char* text) +{ + nbgl_useCaseStatus(text, true, ui_idle_flow); +} #endif // HAVE_NBGL From 48627aae1e04090e1836edb7017043e9fef5ef97 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 12 May 2023 18:36:31 +0200 Subject: [PATCH 064/105] nbgl: fix bug where back button was freezing the app --- src/ui_menu_nbgl.c | 1 - src/ui_nbgl.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/ui_menu_nbgl.c b/src/ui_menu_nbgl.c index 7c06742b..95071f62 100644 --- a/src/ui_menu_nbgl.c +++ b/src/ui_menu_nbgl.c @@ -93,7 +93,6 @@ static void ui_menu_settings(void) void ui_idle_flow(void) { - TRACE("RESETTING\n\n"); // We need to make sure the ui context is reset even if the app restarts nbgl_reset_transaction_full_context(); nbgl_useCaseHome("Cardano", &C_cardano_64, NULL, true, diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index d5806aa2..610b8e74 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -143,8 +143,6 @@ static void display_callback(int token, unsigned char index) (void)index; callback_t callback; - release_context(); - switch (token) { case CANCEL_PROMPT_TOKEN: display_cancel(); From 55d8b114485f055c649e3efc1da88237d4f1074a Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 31 May 2023 18:10:49 +0200 Subject: [PATCH 065/105] Makefile: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index bb9370d9..45580ce9 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ APPNAME = "Cardano ADA" APPVERSION_M = 6 APPVERSION_N = 0 -APPVERSION_P = 4 +APPVERSION_P = 5 APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" ifeq ($(BOLOS_SDK),) From 8679e9f8f2bfd91e7fc243704c2f1e13c4d35688 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 12 Jun 2023 16:03:07 +0200 Subject: [PATCH 066/105] deriveAddress: remove useless warning screen --- src/deriveAddress.c | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/src/deriveAddress.c b/src/deriveAddress.c index 6354b9b0..193f9df9 100644 --- a/src/deriveAddress.c +++ b/src/deriveAddress.c @@ -175,24 +175,6 @@ static void deriveAddress_return_ui_runStep() /* ========================== DISPLAY ADDRESS ========================== */ -static void _displayVerifyAddressMsg(ui_callback_fn_t* this_fn) -{ - #ifdef HAVE_BAGL - ui_displayPaginatedText( - "Verify address", - "Make sure it agrees with your computer", - this_fn - ); - #elif defined(HAVE_NBGL) - set_light_confirmation(true); - display_warning( - "Make sure address matches\nwith your computer", - this_fn, - respond_with_user_reject - ); - #endif // HAVE_BAGL -} - static void _displaySpendingInfo_displayAddr(ui_callback_fn_t* this_fn) { #ifdef HAVE_BAGL @@ -259,7 +241,6 @@ static void _displayConfirmAddressPrompt(ui_callback_fn_t* this_fn) static void deriveAddress_display_ui_runStep(); enum { DISPLAY_UI_STEP_WARNING = 200, - DISPLAY_UI_STEP_INSTRUCTIONS, DISPLAY_UI_STEP_SPENDING_INFO, DISPLAY_UI_STEP_STAKING_INFO, DISPLAY_UI_STEP_ADDRESS, @@ -280,7 +261,7 @@ static void deriveAddress_handleDisplay() switch (policy) { #define CASE(policy, step) case policy: {ctx->ui_step=step; break;} CASE(POLICY_PROMPT_WARN_UNUSUAL, DISPLAY_UI_STEP_WARNING); - CASE(POLICY_SHOW_BEFORE_RESPONSE, DISPLAY_UI_STEP_INSTRUCTIONS); + CASE(POLICY_SHOW_BEFORE_RESPONSE, DISPLAY_UI_STEP_SPENDING_INFO); #undef CASE default: THROW(ERR_NOT_IMPLEMENTED); @@ -298,9 +279,6 @@ static void deriveAddress_display_ui_runStep() UI_STEP(DISPLAY_UI_STEP_WARNING) { ui_displayUnusualWarning(this_fn); } - UI_STEP(DISPLAY_UI_STEP_INSTRUCTIONS) { - _displayVerifyAddressMsg(this_fn); - } UI_STEP(DISPLAY_UI_STEP_SPENDING_INFO) { if (determineSpendingChoice(ctx->addressParams.type) == SPENDING_NONE) { // reward address From 8d299d54e043024dde9b13ed908d551db025fdba Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 12 Jun 2023 16:06:39 +0200 Subject: [PATCH 067/105] ui: update some wording --- src/signTx_ui.c | 2 +- src/uiScreens_bagl.c | 4 ++-- src/uiScreens_nbgl.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/signTx_ui.c b/src/signTx_ui.c index 149989a1..ca5b9e52 100644 --- a/src/signTx_ui.c +++ b/src/signTx_ui.c @@ -916,6 +916,6 @@ void signTx_handleWitness_ui_runStep() void endTxStatus(void) { #ifdef HAVE_NBGL - display_status("TRANSACTION\nCONFIRMED"); + display_status("TRANSACTION\nSIGNED"); #endif // HAVE_NBGL } diff --git a/src/uiScreens_bagl.c b/src/uiScreens_bagl.c index 34307ba3..0c2791a7 100644 --- a/src/uiScreens_bagl.c +++ b/src/uiScreens_bagl.c @@ -373,7 +373,7 @@ void ui_displaySpendingInfoScreen( case SPENDING_PATH: { ui_displayPathScreen( - "Spending path", + "Derivation path", &addressParams->spendingKeyPath, callback ); @@ -398,7 +398,7 @@ void ui_displaySpendingInfoScreen( } } -static const char STAKING_HEADING_PATH[] = "Stake key path"; +static const char STAKING_HEADING_PATH[] = "Staking path"; static const char STAKING_HEADING_KEY_HASH[] = "Stake key hash"; static const char STAKING_HEADING_SCRIPT_HASH[] = "Stake script hash"; static const char STAKING_HEADING_POINTER[] = "Stake key pointer"; diff --git a/src/uiScreens_nbgl.c b/src/uiScreens_nbgl.c index 2a2a22bf..db1b7bf9 100644 --- a/src/uiScreens_nbgl.c +++ b/src/uiScreens_nbgl.c @@ -344,7 +344,7 @@ void ui_getSpendingInfoScreen( switch (determineSpendingChoice(addressParams->type)) { case SPENDING_PATH: { - snprintf(line1, line1Size, "Spending path"); + snprintf(line1, line1Size, "Derivation path"); ui_getPathScreen( line2, line2Size, @@ -372,7 +372,7 @@ void ui_getSpendingInfoScreen( } } -static const char STAKING_HEADING_PATH[] = "Stake key path"; +static const char STAKING_HEADING_PATH[] = "Staking path"; static const char STAKING_HEADING_KEY_HASH[] = "Stake key hash"; static const char STAKING_HEADING_SCRIPT_HASH[] = "Stake script hash"; static const char STAKING_HEADING_POINTER[] = "Stake key pointer"; From 15fe7b1dfad087f6de575edf3ed00950de9c99c6 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 13 Jun 2023 11:40:00 +0200 Subject: [PATCH 068/105] getPublicKeys_ui: use API instead of direct call to nbgl --- src/getPublicKeys_ui.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/getPublicKeys_ui.c b/src/getPublicKeys_ui.c index a083693e..6d4d8635 100644 --- a/src/getPublicKeys_ui.c +++ b/src/getPublicKeys_ui.c @@ -107,7 +107,7 @@ void getPublicKeys_respondOneKey_ui_runStep() if (ctx->currentPath == ctx->numPaths) { #ifdef HAVE_NBGL if (!ctx->silent_export) { - nbgl_useCaseStatus("PUBLIC KEY\nEXPORTED", true, ui_idle_flow); + display_status("PUBLIC KEY\nEXPORTED"); } #endif // HAVE_NBGL keys_advanceStage(); From 5e5dd8b128078bb7ebc160d07cc49cae0c666a15 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 13 Jun 2023 11:56:11 +0200 Subject: [PATCH 069/105] nbgl: add calls to nbgl_reset_transaction_full_context as the callback to useCaseStatus is not always called --- src/ui_nbgl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index 610b8e74..fdc61b3b 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -238,6 +238,7 @@ static void cancellation_status_callback(void) uiContext.rejectedCallback(); } ui_idle_flow(); + nbgl_reset_transaction_full_context(); } static void display_cancel_status(void) @@ -342,6 +343,7 @@ static void confirmation_status_callback(void) { if (uiContext.confirmedStatus) { nbgl_useCaseStatus(uiContext.confirmedStatus, true, ui_idle_flow); + nbgl_reset_transaction_full_context(); } else { nbgl_useCaseSpinner("Processing"); } @@ -563,5 +565,6 @@ void display_error(void) void display_status(const char* text) { nbgl_useCaseStatus(text, true, ui_idle_flow); + nbgl_reset_transaction_full_context(); } #endif // HAVE_NBGL From f40e342da79ee91ed342f494cc49ea3cd3e010d7 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 13 Jun 2023 12:00:54 +0200 Subject: [PATCH 070/105] nbgl: confirmation_status_callback does not need to be triggered through callback --- src/ui_nbgl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index fdc61b3b..8ed614bc 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -357,7 +357,7 @@ static void display_confirmation_status(void) } if (!uiContext.no_approved_status) { - trigger_callback(&confirmation_status_callback); + confirmation_status_callback(); } } From 54dc1b9aec75644d683fe7f97928b6f30a54d4a7 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 13 Jun 2023 12:06:25 +0200 Subject: [PATCH 071/105] nbgl: Make sure Sign Transaction always has strong confirmation screen --- src/signTx_ui.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/signTx_ui.c b/src/signTx_ui.c index ca5b9e52..37609910 100644 --- a/src/signTx_ui.c +++ b/src/signTx_ui.c @@ -832,6 +832,7 @@ void signTx_handleConfirm_ui_runStep() respond_with_user_reject ); #elif defined(HAVE_NBGL) + set_light_confirmation(false); display_confirmation("Sign\ntransaction", "", NULL, "Transaction\nrejected", this_fn, respond_with_user_reject); #endif // HAVE_BAGL } From 96ac8008386cd16cca4ab39cc2b66431ab037651 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Thu, 15 Jun 2023 14:39:07 +0200 Subject: [PATCH 072/105] Makefile: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 45580ce9..2760317d 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ APPNAME = "Cardano ADA" APPVERSION_M = 6 APPVERSION_N = 0 -APPVERSION_P = 5 +APPVERSION_P = 6 APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" ifeq ($(BOLOS_SDK),) From 68ae0a933da2d4b6ff2c9e347694b903ab332403 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Thu, 22 Jun 2023 11:28:32 +0200 Subject: [PATCH 073/105] nbgl: fix some wording --- src/signTx_ui.c | 2 +- src/ui_nbgl.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/signTx_ui.c b/src/signTx_ui.c index 37609910..60b8c201 100644 --- a/src/signTx_ui.c +++ b/src/signTx_ui.c @@ -833,7 +833,7 @@ void signTx_handleConfirm_ui_runStep() ); #elif defined(HAVE_NBGL) set_light_confirmation(false); - display_confirmation("Sign\ntransaction", "", NULL, "Transaction\nrejected", this_fn, respond_with_user_reject); + display_confirmation("Sign\ntransaction?", "", NULL, "Transaction\nrejected", this_fn, respond_with_user_reject); #endif // HAVE_BAGL } UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index 8ed614bc..99bfb095 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -227,7 +227,7 @@ static void display_cancel(void) if (uiContext.lightConfirmation) { display_cancel_status(); } else { - nbgl_useCaseConfirm("Reject ?", NULL, "Yes, Reject", + nbgl_useCaseConfirm("Reject transaction?", NULL, "Yes, reject", "Go back to transaction", display_cancel_status); } } @@ -248,7 +248,7 @@ static void display_cancel_status(void) if (uiContext.rejectedStatus) { nbgl_useCaseStatus(uiContext.rejectedStatus, false, cancellation_status_callback); } else { - nbgl_useCaseStatus("Action rejected", false, cancellation_status_callback); + nbgl_useCaseStatus("Transaction rejected", false, cancellation_status_callback); } } From fd556c08cfffff76cdd20aaa0985c17c061342dc Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 23 Jun 2023 11:18:18 +0200 Subject: [PATCH 074/105] nbgl: use display_confirmation_no_approved_status when needed --- src/signTx_ui.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/signTx_ui.c b/src/signTx_ui.c index 60b8c201..96164210 100644 --- a/src/signTx_ui.c +++ b/src/signTx_ui.c @@ -833,7 +833,7 @@ void signTx_handleConfirm_ui_runStep() ); #elif defined(HAVE_NBGL) set_light_confirmation(false); - display_confirmation("Sign\ntransaction?", "", NULL, "Transaction\nrejected", this_fn, respond_with_user_reject); + display_confirmation_no_approved_status("Sign\ntransaction?", "", "Transaction\nrejected", this_fn, respond_with_user_reject); #endif // HAVE_BAGL } UI_STEP(HANDLE_CONFIRM_STEP_RESPOND) { @@ -895,7 +895,7 @@ void signTx_handleWitness_ui_runStep() _wipeWitnessSignature ); #elif defined(HAVE_NBGL) - display_confirmation("Sign using witness", "", NULL, "Signature\nrejected", this_fn, _wipeWitnessSignature); + display_confirmation_no_approved_status("Sign using witness", "", "Signature\nrejected", this_fn, _wipeWitnessSignature); #endif // HAVE_BAGL } UI_STEP(HANDLE_WITNESS_STEP_RESPOND) { From 4257ed103f2d75825b99ca4de7d6bfc5611b823f Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 23 Jun 2023 17:37:42 +0200 Subject: [PATCH 075/105] nbgl: don't reset tx_context when calling status directly --- src/ui_nbgl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index 99bfb095..643014c0 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -565,6 +565,5 @@ void display_error(void) void display_status(const char* text) { nbgl_useCaseStatus(text, true, ui_idle_flow); - nbgl_reset_transaction_full_context(); } #endif // HAVE_NBGL From a43ad7b767b53015b7f8c85d2cf34ae5a7c0565f Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 26 Jun 2023 14:14:03 +0200 Subject: [PATCH 076/105] getPublicKeys_ui.c: revert to previous message for bagl --- src/getPublicKeys_ui.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/getPublicKeys_ui.c b/src/getPublicKeys_ui.c index 6d4d8635..038f11cf 100644 --- a/src/getPublicKeys_ui.c +++ b/src/getPublicKeys_ui.c @@ -134,7 +134,11 @@ void getPublicKeys_handleInit_ui_runStep() explicit_bzero(secondLine, SIZEOF(secondLine)); STATIC_ASSERT(sizeof(ctx->numPaths) <= sizeof(unsigned), "oversized type for %u"); STATIC_ASSERT(!IS_SIGNED(ctx->numPaths), "signed type for %u"); + #ifdef HAVE_BAGL + snprintf(secondLine, SIZEOF(secondLine), "%u public keys?", ctx->numPaths); + #elif defined(HAVE_NBGL) snprintf(secondLine, SIZEOF(secondLine), "Allow the Cardano app to\nexport your %u public keys?", ctx->numPaths); + #endif // HAVE_BAGL // make sure all the information is displayed to the user ASSERT(strlen(secondLine) + 1 < SIZEOF(secondLine)); From 5fe329d64a781c5ae752d339eea364458f7dc52e Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 26 Jun 2023 16:29:19 +0200 Subject: [PATCH 077/105] ui_nbgl: increase max text string value --- src/ui_nbgl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index 643014c0..74904bb4 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -24,7 +24,7 @@ #define MAX_LINE_PER_PAGE_COUNT NB_MAX_LINES_IN_REVIEW #define MAX_TAG_TITLE_LINE_LENGTH 30 #define MAX_TAG_CONTENT_LENGTH 200 -#define MAX_TEXT_STRING 50 +#define MAX_TEXT_STRING 60 #define PENDING_ELEMENT_INDEX NB_MAX_DISPLAYED_PAIRS_IN_REVIEW enum { CANCEL_PROMPT_TOKEN = 1, From 31043aed5d3890c1ab0f3c49ae1bd1db67ea8759 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 26 Jun 2023 16:29:41 +0200 Subject: [PATCH 078/105] Revert "nbgl: confirmation_status_callback does not need to be triggered through callback" This reverts commit f40e342da79ee91ed342f494cc49ea3cd3e010d7. --- src/ui_nbgl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index 74904bb4..30e47fbf 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -357,7 +357,7 @@ static void display_confirmation_status(void) } if (!uiContext.no_approved_status) { - confirmation_status_callback(); + trigger_callback(&confirmation_status_callback); } } From a20df3a668a7a011140bebe8c1afdfe5f5190afa Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 23 Jun 2023 11:14:23 +0200 Subject: [PATCH 079/105] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2760317d..e9a67734 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ APPNAME = "Cardano ADA" APPVERSION_M = 6 APPVERSION_N = 0 -APPVERSION_P = 6 +APPVERSION_P = 7 APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" ifeq ($(BOLOS_SDK),) From c18530b4fd2f62749c9d7838f9e83f8d79b5b3cc Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 17 Jul 2023 09:49:24 +0200 Subject: [PATCH 080/105] icons: update logo for Stax --- glyphs/cardano_64.gif | Bin 313 -> 679 bytes icon_ada_stax.gif | Bin 130 -> 355 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/glyphs/cardano_64.gif b/glyphs/cardano_64.gif index d9fd0ca43a2f1aa543bbe9acfecf4a4e2b9545a7..b0e396f1a6e43ac0621a9163ced0314b44a38391 100644 GIT binary patch literal 679 zcmV;Y0$BY=Nk%w1VL$*t0J8u9>gwu?i;J(XubrKpdU|@o!ot?p)@f;JSy@>O3=B$2 zN+>8O78VveJ39aX0RR90A^8LV00000EC2ui06+jh000F4@X1N5y*TU5yZ>M)j$~<` zXqpxYW2mJNY>ML?8!^BZU<(?8ZI=l+5&#|rz(~9_hNOnIQ1-0Ytahs%G!#;gVX+`` zB?jB=Vt7_+$1t~`R#@P;N<%H@B93kn0%{I{4+RWsXG?t#gK9umN&t}{Og2>_0frm~ z2@V7!0|AX3e-4!$LJpaW4~Y(D9RLdnvKa@73o{b|3#_3W0%R(b6{l*!2ZRm?O9GrQ z1D`H}%yDVgkp{55RI3OG3dg7-6>Z0WAkLCqT21$lE*{IepR#dSTBsIXfMAGor3S(Ozl_`nc9W!#zTB z;F+On!9XeiH5T-_nN>qnH9gTXaK|yE2Xi*6YGAw1)tD9s>{2*@v4PBu6(;VYFf1eD zhk+6zUC4~C&j2rZ?5y@68zCgGw4q^_l*dhX4Al(4tMCD`1X;kLrYC^TwLIyvY<|Mp z27rH}J14TG#jKpKic(v4Bp3vl%ohl=D(K4r1BV)>sRePgCzqC`H#}NCE5I!eLi&C% zps~Y1pd$n{A5rS44Nd?~W?9DI@C5q~^x;WVIIe8vKv#M+bcY)LaRD5B78FoQLi#Cj zkx7;)&_H;Pb?D)TAJPx%GnvkE|#PhZH!4-36F|C;=jz>FDE+ NKn5w~kQGD#06YDs6E*+< literal 313 zcmV-90mlAENk%w1VL$*t0Du4h00030|NkNW5kqoiVRU6=Aa`kWXdp*PO;7+V00000 zKmb4h00RDukEzS;52Kv4+KVFqx!>)DAT&N@n4FEuu;>fN@=U+3#?{M~Q@pO=^-@EG z5NP}bmBicZxO6d*q$w2xMOv?hZOaMFRwv@F_gfQ|)L@yIJ%SI*qBq>kKICEhfE=%; z7Z_u=_b1r)p>lXf#07ZL_lUMrG&v}N87Aq_SZC?yxgv@<+GKgyNgBGC)5?-M%E?;f z)HjIA$C~VGcu8Ja;jp L#srNh3IG5*N1~F3 diff --git a/icon_ada_stax.gif b/icon_ada_stax.gif index 1bd3d3d49a55a12134570061457ceb3fbbf02605..4a45c4973e232f8552b27af06e1f268b0b6e5219 100644 GIT binary patch literal 355 zcmV-p0i6CvNk%w1VITk?0J8u9i;Ih$otnu7)nY?4Gj&iudgmH zF2cgX*4EbQ>goUh0RR90A^8LV00000EC2ui03ZM$000F4@X1N5y*TS_n^i>BFdU@> z)i9)CDS0LAN{cKeGnF{Ul%NuYW08BEXbuPI0U#_lfv3oz$S?pGhC^_vy@(cp!{&o6 zNDYI-a7L^>3GhRX(IOgwB(IA_4KM;!j|T=TMH38aToqz$ z8Uh{w4mb}&fI50DJ1Y#E1tbFwKm>ZENJ&+N4p(VYmGSr1_zG{2AhvFnFbAp zTYQQS2GA}GNe!Y&1qXTo4Q|90atk-@1v*?>$#O;n06V#D Bc$5GD literal 130 zcmZ?wbhEHbRA5kGXkY+=|Ns9h{u6XAN=+*^z^Sh z{g!|6oGno->+bDI{mklcqgRG=;bhHKQ!I~dTv2OuIxcHp)8~(iU2_hK`L!2)jdByX fRFRxla5B+V({f(SjlS=%8M}`^*<=~Wz+epk({eO8 From 108e9b7fe31597db0ebce93ff616525de30fd537 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 17 Jul 2023 10:41:47 +0200 Subject: [PATCH 081/105] Settings: update according to latest guidelines --- src/ui_menu_nbgl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ui_menu_nbgl.c b/src/ui_menu_nbgl.c index 95071f62..3d11377a 100644 --- a/src/ui_menu_nbgl.c +++ b/src/ui_menu_nbgl.c @@ -50,6 +50,11 @@ static void exit(void) static bool settings_navigation_callback(uint8_t page, nbgl_pageContent_t* content) { if (page == 0) { + content->type = INFOS_LIST; + content->infosList.nbInfos = NB_INFO_FIELDS; + content->infosList.infoTypes = (const char**)infoTypes; + content->infosList.infoContents = (const char**)infoContents; + } else if (page == 1) { switches[0].text = "Expert mode"; switches[0].subText = "Enable expert mode"; switches[0].token = SWITCH_APP_MODE_TOKEN; @@ -59,11 +64,6 @@ static bool settings_navigation_callback(uint8_t page, nbgl_pageContent_t* conte content->type = SWITCHES_LIST; content->switchesList.nbSwitches = NB_SETTINGS_SWITCHES; content->switchesList.switches = (nbgl_layoutSwitch_t*)switches; - } else if (page == 1) { - content->type = INFOS_LIST; - content->infosList.nbInfos = NB_INFO_FIELDS; - content->infosList.infoTypes = (const char**)infoTypes; - content->infosList.infoContents = (const char**)infoContents; } else { return false; } From 6d17e0a891f4031e380debafbebf14869f9eacf7 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 17 Jul 2023 09:49:44 +0200 Subject: [PATCH 082/105] Makefile: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e9a67734..2abd3fb6 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ APPNAME = "Cardano ADA" APPVERSION_M = 6 APPVERSION_N = 0 -APPVERSION_P = 7 +APPVERSION_P = 8 APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" ifeq ($(BOLOS_SDK),) From b5b444bdb6dc2e51351566a665a32ac2e79cd167 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 25 Jul 2023 17:58:47 +0200 Subject: [PATCH 083/105] signTx_ui: fix build --- src/signTx_ui.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/signTx_ui.c b/src/signTx_ui.c index 96164210..97b71c73 100644 --- a/src/signTx_ui.c +++ b/src/signTx_ui.c @@ -728,7 +728,7 @@ void signTx_handleRequiredSigner_ui_runStep() UI_STEP(HANDLE_REQUIRED_SIGNERS_STEP_DISPLAY) { switch (BODY_CTX->stageData.requiredSigner.type) { - case REQUIRED_SIGNER_WITH_PATH: + case REQUIRED_SIGNER_WITH_PATH: { #ifdef HAVE_BAGL ui_displayPathScreen("Required signer", &BODY_CTX->stageData.requiredSigner.keyPath, this_fn); #elif defined(HAVE_NBGL) @@ -737,7 +737,8 @@ void signTx_handleRequiredSigner_ui_runStep() fill_and_display_if_required("Required signer", pathStr, this_fn, respond_with_user_reject); #endif // HAVE_BAGL break; - case REQUIRED_SIGNER_WITH_HASH: + } + case REQUIRED_SIGNER_WITH_HASH: { #ifdef HAVE_BAGL ui_displayBech32Screen( "Required signer", @@ -752,6 +753,7 @@ void signTx_handleRequiredSigner_ui_runStep() fill_and_display_if_required("Required signer", encodedStr, this_fn, respond_with_user_reject); #endif // HAVE_BAGL break; + } default: ASSERT(false); From fe59d36944693175df4b8fd400de6becc59ffe74 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Thu, 3 Aug 2023 10:36:59 +0200 Subject: [PATCH 084/105] QR code source path is now used explicitly --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 2abd3fb6..6cb35b11 100644 --- a/Makefile +++ b/Makefile @@ -96,6 +96,7 @@ endif ifeq ($(TARGET_NAME),TARGET_STAX) DEFINES += NBGL_QRCODE +SDK_SOURCE_PATH += qrcode endif DEFINES += HAVE_BAGL_ELLIPSIS # long label truncation feature DEFINES += HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX From 9138a48872699024eee33a49c241ac64e9ec2596 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 8 Aug 2023 18:01:16 +0200 Subject: [PATCH 085/105] Bump Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6cb35b11..c2748e4f 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ APPNAME = "Cardano ADA" APPVERSION_M = 6 APPVERSION_N = 0 -APPVERSION_P = 8 +APPVERSION_P = 9 APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" ifeq ($(BOLOS_SDK),) From 8ac938cf0120de7077a242f22a60c26f289125c2 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 2 Aug 2023 18:01:57 +0200 Subject: [PATCH 086/105] nbgl: confirmation_status_callback does not need to be triggered through callback --- src/ui_nbgl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index 30e47fbf..74904bb4 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -357,7 +357,7 @@ static void display_confirmation_status(void) } if (!uiContext.no_approved_status) { - trigger_callback(&confirmation_status_callback); + confirmation_status_callback(); } } From 359b16ddcf83e532e759980a2ba7adf7ebdafefd Mon Sep 17 00:00:00 2001 From: Xavier Chapron Date: Wed, 28 Jun 2023 11:41:06 +0200 Subject: [PATCH 087/105] update crypto calls --- src/crypto.c | 151 +++++++++++++++++++++++++++++++++++++++ src/crypto.h | 21 ++++++ src/hash.h | 50 ++++++++----- src/keyDerivation.c | 121 ++++++++----------------------- src/keyDerivation.h | 16 ----- src/keyDerivation_test.c | 119 ++---------------------------- src/messageSigning.c | 74 +++++++------------ src/ui_nbgl.c | 2 +- 8 files changed, 262 insertions(+), 292 deletions(-) create mode 100644 src/crypto.c create mode 100644 src/crypto.h diff --git a/src/crypto.c b/src/crypto.c new file mode 100644 index 00000000..92cfef08 --- /dev/null +++ b/src/crypto.c @@ -0,0 +1,151 @@ +/***************************************************************************** + * Ledger SDK. + * (c) 2023 Ledger SAS. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *****************************************************************************/ +#include // uint*_t +#include // memset, explicit_bzero +#include // bool + +#include "cx.h" +#include "os.h" + +static cx_err_t crypto_init_privkey( + const uint32_t* path, + size_t path_len, + cx_ecfp_256_extended_private_key_t* privkey, + uint8_t* chain_code) +{ + cx_err_t error = CX_OK; + uint8_t raw_privkey[64]; + + // Derive private key according to BIP32 path + CX_CHECK(os_derive_bip32_no_throw(CX_CURVE_Ed25519, + path, + path_len, + raw_privkey, + chain_code)); + + // Init privkey from raw + // Do not use cx_ecfp_init_private_key_no_throw as it doesn't + // support 64 bytes for CX_CURVE_Ed25519 curve + privkey->curve = CX_CURVE_Ed25519; + privkey->d_len = sizeof(privkey->d); + memmove(privkey->d, raw_privkey, sizeof(privkey->d)); + +end: + explicit_bzero(raw_privkey, sizeof(raw_privkey)); + + // CX_CHECK above would set the value of `error` in case of error + if (error != CX_OK) { + // Make sure the caller doesn't use uninitialized data in case + // the return code is not checked. + explicit_bzero(privkey, sizeof(cx_ecfp_256_extended_private_key_t)); + } + return error; +} + +WARN_UNUSED_RESULT cx_err_t crypto_get_pubkey( + const uint32_t* path, + size_t path_len, + uint8_t raw_pubkey[static 65], + uint8_t* chain_code) +{ + cx_err_t error = CX_OK; + + cx_ecfp_256_extended_private_key_t privkey; + cx_ecfp_256_public_key_t pubkey; + + // Derive private key according to BIP32 path + CX_CHECK(crypto_init_privkey(path, + path_len, + &privkey, + chain_code)); + + // Generate associated pubkey + // Do not use cx_ecfp_generate_pair2_no_throw as it doesn't + // support 64 bytes for CX_CURVE_Ed25519 curve + CX_CHECK(cx_eddsa_get_public_key_no_throw((const struct cx_ecfp_256_private_key_s*) &privkey, + CX_SHA512, + &pubkey, + NULL, + 0, + NULL, + 0)); + + // Check pubkey length then copy it to raw_pubkey + if (pubkey.W_len != 65) { + error = CX_EC_INVALID_CURVE; + goto end; + } + memmove(raw_pubkey, pubkey.W, pubkey.W_len); + +end: + explicit_bzero(&privkey, sizeof(privkey)); + + // CX_CHECK above would set the value of `error` in case of error + if (error != CX_OK) { + // Make sure the caller doesn't use uninitialized data in case + // the return code is not checked. + explicit_bzero(raw_pubkey, 65); + } + return error; +} + + +WARN_UNUSED_RESULT cx_err_t crypto_eddsa_sign( + const uint32_t* path, + size_t path_len, + const uint8_t* hash, + size_t hash_len, + uint8_t* sig, + size_t* sig_len) +{ + cx_err_t error = CX_OK; + cx_ecfp_256_extended_private_key_t privkey; + size_t size; + size_t buf_len = *sig_len; + + if (sig_len == NULL) { + error = CX_INVALID_PARAMETER_VALUE; + goto end; + } + // Derive private key according to BIP32 path + CX_CHECK(crypto_init_privkey(path, + path_len, + &privkey, + NULL)); + + + CX_CHECK(cx_eddsa_sign_no_throw((const struct cx_ecfp_256_private_key_s*) &privkey, + CX_SHA512, + hash, + hash_len, + sig, + *sig_len)); + + CX_CHECK(cx_ecdomain_parameters_length(CX_CURVE_Ed25519, &size)); + *sig_len = size * 2; + +end: + explicit_bzero(&privkey, sizeof(privkey)); + + // CX_CHECK above would set the value of `error` in case of error + if (error != CX_OK) { + // Make sure the caller doesn't use uninitialized data in case + // the return code is not checked. + explicit_bzero(sig, buf_len); + } + return error; +} diff --git a/src/crypto.h b/src/crypto.h new file mode 100644 index 00000000..da41bd3d --- /dev/null +++ b/src/crypto.h @@ -0,0 +1,21 @@ +#pragma once + +#include // uint*_t + +#include "os.h" +#include "cx.h" + +WARN_UNUSED_RESULT cx_err_t crypto_get_pubkey( + const uint32_t* path, + size_t path_len, + uint8_t raw_pubkey[static 65], + uint8_t* chain_code); + + +WARN_UNUSED_RESULT cx_err_t crypto_eddsa_sign( + const uint32_t* path, + size_t path_len, + const uint8_t* hash, + size_t hash_len, + uint8_t* sig, + size_t* sig_len); diff --git a/src/hash.h b/src/hash.h index 5a2661ee..4deda24b 100644 --- a/src/hash.h +++ b/src/hash.h @@ -34,10 +34,14 @@ enum { ) \ { \ STATIC_ASSERT( bits == CIPHER##_##bits##_SIZE * 8, "bad cipher size"); \ - cx_##cipher##_init( \ - & ctx->cx_ctx, \ - CIPHER##_##bits##_SIZE * 8 \ - );\ + cx_err_t error = cx_##cipher##_init_no_throw( \ + & ctx->cx_ctx, \ + CIPHER##_##bits##_SIZE * 8 \ + );\ + if (error != CX_OK) { \ + PRINTF("error: %d", error); \ + ASSERT(false); \ + } \ ctx->initialized_magic = HASH_CONTEXT_INITIALIZED_MAGIC; \ } \ \ @@ -46,13 +50,17 @@ enum { const uint8_t* inBuffer, size_t inSize \ ) { \ ASSERT(ctx->initialized_magic == HASH_CONTEXT_INITIALIZED_MAGIC); \ - cx_hash( \ - & ctx->cx_ctx.header, \ - 0, /* Do not output the hash, yet */ \ - inBuffer, \ - inSize, \ - NULL, 0 \ - ); \ + cx_err_t error = cx_hash_no_throw( \ + & ctx->cx_ctx.header, \ + 0, /* Do not output the hash, yet */ \ + inBuffer, \ + inSize, \ + NULL, 0 \ + ); \ + if (error != CX_OK) { \ + PRINTF("error: %d", error); \ + ASSERT(false); \ + } \ } \ \ static __attribute__((always_inline, unused)) void cipher##_##bits##_finalize( \ @@ -61,14 +69,18 @@ enum { ) { \ ASSERT(ctx->initialized_magic == HASH_CONTEXT_INITIALIZED_MAGIC); \ ASSERT(outSize == CIPHER##_##bits##_SIZE); \ - cx_hash( \ - & ctx->cx_ctx.header, \ - CX_LAST, /* Output the hash */ \ - NULL, \ - 0, \ - outBuffer, \ - CIPHER##_##bits##_SIZE \ - ); \ + cx_err_t error = cx_hash_no_throw( \ + & ctx->cx_ctx.header, \ + CX_LAST, /* Output the hash */ \ + NULL, \ + 0, \ + outBuffer, \ + CIPHER##_##bits##_SIZE \ + ); \ + if (error != CX_OK) { \ + PRINTF("error: %d", error); \ + ASSERT(false); \ + } \ } \ /* Convenience function to make all in one step */ \ static __attribute__((always_inline, unused)) void cipher##_##bits##_hash( \ diff --git a/src/keyDerivation.c b/src/keyDerivation.c index 71cded97..6e820042 100644 --- a/src/keyDerivation.c +++ b/src/keyDerivation.c @@ -11,86 +11,22 @@ #include "endian.h" #include "cardano.h" #include "securityPolicy.h" +#include "crypto.h" -void derivePrivateKey( - const bip44_path_t* pathSpec, - chain_code_t* chainCode, - privateKey_t* privateKey -) -{ - // Sanity check - ASSERT(pathSpec->length <= ARRAY_LEN(pathSpec->path)); - - // if the path is invalid, it's a bug in previous validation - ASSERT(policyForDerivePrivateKey(pathSpec) != POLICY_DENY); - - uint8_t privateKeyRawBuffer[64] = {0}; - - STATIC_ASSERT(SIZEOF(chainCode->code) == 32, "bad chain code length"); - explicit_bzero(chainCode->code, SIZEOF(chainCode->code)); - - BEGIN_TRY { - TRY { - STATIC_ASSERT(CX_APILEVEL >= 5, "unsupported api level"); - STATIC_ASSERT(SIZEOF(privateKey->d) == 64, "bad private key length"); - #ifndef FUZZING - io_seproxyhal_io_heartbeat(); - os_perso_derive_node_bip32( - CX_CURVE_Ed25519, - pathSpec->path, - pathSpec->length, - privateKeyRawBuffer, - chainCode->code); - io_seproxyhal_io_heartbeat(); - #endif - // We should do cx_ecfp_init_private_key here, but it does not work in SDK < 1.5.4, - // should work with the new SDK - privateKey->curve = CX_CURVE_Ed25519; - privateKey->d_len = 64; - memmove(privateKey->d, privateKeyRawBuffer, 64); - } - FINALLY { - explicit_bzero(privateKeyRawBuffer, SIZEOF(privateKeyRawBuffer)); - } - } END_TRY; -} - - -void deriveRawPublicKey( - const privateKey_t* privateKey, - cx_ecfp_public_key_t* publicKey -) -{ - #ifndef FUZZING - // We should do cx_ecfp_generate_pair here, but it does not work in SDK < 1.5.4, - // should work with the new SDK - io_seproxyhal_io_heartbeat(); - cx_eddsa_get_public_key( - // cx_eddsa has a special case struct for Cardano's private keys - // but signature is standard - (const struct cx_ecfp_256_private_key_s*) privateKey, - CX_SHA512, - publicKey, - NULL, 0, NULL, 0); - io_seproxyhal_io_heartbeat(); - #endif -} - -void extractRawPublicKey( - const cx_ecfp_public_key_t* publicKey, +static void extractRawPublicKey( + uint8_t rawPubkey[static 65], uint8_t* outBuffer, size_t outSize ) { // copy public key little endian to big endian ASSERT(outSize == 32); - STATIC_ASSERT(SIZEOF(publicKey->W) == 65, "bad public key length"); uint8_t i; for (i = 0; i < 32; i++) { - outBuffer[i] = publicKey->W[64 - i]; + outBuffer[i] = rawPubkey[64 - i]; } - if ((publicKey->W[32] & 1) != 0) { + if ((rawPubkey[32] & 1) != 0) { outBuffer[31] |= 0x80; } } @@ -102,35 +38,34 @@ void deriveExtendedPublicKey( extendedPublicKey_t* out ) { - privateKey_t privateKey; - chain_code_t chainCode; + uint8_t rawPubkey[65]; + uint8_t chainCode[CHAIN_CODE_SIZE]; STATIC_ASSERT(SIZEOF(*out) == CHAIN_CODE_SIZE + PUBLIC_KEY_SIZE, "bad ext pub key size"); - BEGIN_TRY { - TRY { - derivePrivateKey( - pathSpec, - &chainCode, - &privateKey - ); - - // Pubkey part - cx_ecfp_public_key_t publicKey; + // Sanity check + ASSERT(pathSpec->length <= ARRAY_LEN(pathSpec->path)); - deriveRawPublicKey(&privateKey, &publicKey); + // if the path is invalid, it's a bug in previous validation + ASSERT(policyForDerivePrivateKey(pathSpec) != POLICY_DENY); - STATIC_ASSERT(SIZEOF(out->pubKey) == PUBLIC_KEY_SIZE, "bad pub key size"); + #ifndef FUZZING + { + cx_err_t error = crypto_get_pubkey(pathSpec->path, + pathSpec->length, + rawPubkey, + chainCode); + if (error != CX_OK) { + PRINTF("error: %d", error); + ASSERT(false); + } + } + #endif - extractRawPublicKey(&publicKey, out->pubKey, SIZEOF(out->pubKey)); + extractRawPublicKey(rawPubkey, out->pubKey, SIZEOF(out->pubKey)); - // Chain code (we copy it second to avoid mid-updates extractRawPublicKey throws - STATIC_ASSERT(CHAIN_CODE_SIZE == SIZEOF(out->chainCode), "bad chain code size"); - STATIC_ASSERT(CHAIN_CODE_SIZE == SIZEOF(chainCode.code), "bad chain code size"); - memmove(out->chainCode, chainCode.code, CHAIN_CODE_SIZE); - } - FINALLY { - explicit_bzero(&privateKey, SIZEOF(privateKey)); - } - } END_TRY; + // Chain code (we copy it second to avoid mid-updates extractRawPublicKey throws + STATIC_ASSERT(CHAIN_CODE_SIZE == SIZEOF(out->chainCode), "bad chain code size"); + STATIC_ASSERT(CHAIN_CODE_SIZE == SIZEOF(chainCode), "bad chain code size"); + memmove(out->chainCode, chainCode, CHAIN_CODE_SIZE); } diff --git a/src/keyDerivation.h b/src/keyDerivation.h index 04f22726..b6ce9984 100644 --- a/src/keyDerivation.h +++ b/src/keyDerivation.h @@ -20,28 +20,12 @@ typedef struct { uint8_t chainCode[CHAIN_CODE_SIZE]; } extendedPublicKey_t; -void derivePrivateKey( - const bip44_path_t* pathSpec, - chain_code_t* chainCode, // 32 byte output - privateKey_t* privateKey // output -); - void deriveExtendedPublicKey( const bip44_path_t* pathSpec, extendedPublicKey_t* out ); -void deriveRawPublicKey( - const privateKey_t* privateKey, - cx_ecfp_public_key_t* publicKey // output -); - -void extractRawPublicKey( - const cx_ecfp_public_key_t* publicKey, - uint8_t* outBuffer, size_t outSize -); - #ifdef DEVEL void run_key_derivation_test(); diff --git a/src/keyDerivation_test.c b/src/keyDerivation_test.c index ab99df82..dde850c7 100644 --- a/src/keyDerivation_test.c +++ b/src/keyDerivation_test.c @@ -10,67 +10,6 @@ static void pathSpec_init(bip44_path_t* pathSpec, const uint32_t* pathArray, uin memmove(pathSpec->path, pathArray, pathLength * 4); } -void testcase_derivePrivateKey(uint32_t* path, uint32_t pathLen, const char* expectedHex) -{ - PRINTF("testcase_derivePrivateKey "); - - bip44_path_t pathSpec; - ASSERT(pathLen <= BIP44_MAX_PATH_ELEMENTS); - pathSpec_init(&pathSpec, path, pathLen); - BIP44_PRINTF(&pathSpec); - PRINTF("\n"); - - uint8_t expected[64] = {0}; - size_t expectedSize = decode_hex(expectedHex, expected, SIZEOF(expected)); - - chain_code_t chainCode; - privateKey_t privateKey; - derivePrivateKey(&pathSpec, &chainCode, &privateKey); - EXPECT_EQ_BYTES(expected, privateKey.d, expectedSize); -} - -void testPrivateKeyDerivation() -{ - -#define HD HARDENED_BIP32 - -#define TESTCASE(path_, expectedHex_) \ - { \ - uint32_t path[] = { UNWRAP path_ }; \ - testcase_derivePrivateKey(path, ARRAY_LEN(path), expectedHex_); \ - } - - - // Note: Failing tests here? Did you load testing mnemonic - // "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"? - - TESTCASE( - (HD + 44, HD + 1815, HD + 1), - - "5878bdf06af259f1419324680c4d4ce05b4343895b697144d874749925e69d41" - "648e7e50061809207f81dac36b73cd8fab2325d49d26bc65ebbb696ea59c45b8" - ); - - TESTCASE( - (HD + 1852, HD + 1815, HD + 1, 0, HD + 55), - - "08671b6f39031f2fc7bcebff7b85aec4c27787fc6a12f7f8bbfb28902ae69d41" - "85751aae1484fb26c53f8e4c35b943d11449b52e5863779821fcc49cddf60792" - ); -#undef TESTCASE - -#define TESTCASE(path_, error_) \ - { \ - uint32_t path[] = { UNWRAP path_ }; \ - EXPECT_THROWS(testcase_derivePrivateKey(path, ARRAY_LEN(path), ""), error_ ); \ - } - - TESTCASE( (HD + 43, HD + 1815), ERR_ASSERT); - TESTCASE( (HD + 44, 1815, HD + 1), ERR_ASSERT); - TESTCASE( (HD + 44, HD + 33, HD + 1), ERR_ASSERT); -#undef TESTCASE -} - void testcase_derivePublicKey(uint32_t* path, uint32_t pathLen, const char* expected) { PRINTF("testcase_derivePublicKey "); @@ -81,19 +20,16 @@ void testcase_derivePublicKey(uint32_t* path, uint32_t pathLen, const char* expe BIP44_PRINTF(&pathSpec); PRINTF("\n"); - chain_code_t chainCode; - privateKey_t privateKey; - derivePrivateKey(&pathSpec, &chainCode, &privateKey); - cx_ecfp_public_key_t publicKey; - deriveRawPublicKey(&privateKey, &publicKey); - uint8_t publicKeyRaw[32] = {0}; - extractRawPublicKey(&publicKey, publicKeyRaw, SIZEOF(publicKeyRaw)); + extendedPublicKey_t extPubKey; + deriveExtendedPublicKey(&pathSpec, &extPubKey); uint8_t expectedBuffer[32] = {0}; decode_hex(expected, expectedBuffer, SIZEOF(expectedBuffer)); - EXPECT_EQ_BYTES(expectedBuffer, publicKeyRaw, SIZEOF(expectedBuffer)); + EXPECT_EQ_BYTES(expectedBuffer, extPubKey.pubKey, SIZEOF(expectedBuffer)); } +#define HD HARDENED_BIP32 + void testPublicKeyDerivation() { #define TESTCASE(path_, expectedHex_) \ @@ -137,57 +73,12 @@ void testPublicKeyDerivation() } -void testcase_deriveChainCode(uint32_t* path, uint32_t pathLen, const char* expectedHex) -{ - PRINTF("testcase_deriveChainCode "); - - chain_code_t chainCode; - privateKey_t privateKey; - - bip44_path_t pathSpec; - pathSpec_init(&pathSpec, path, pathLen); - - BIP44_PRINTF(&pathSpec); - PRINTF("\n"); - - derivePrivateKey(&pathSpec, &chainCode, &privateKey); - - uint8_t expectedBuffer[32] = {0}; - decode_hex(expectedHex, expectedBuffer, 32); - EXPECT_EQ_BYTES(expectedBuffer, chainCode.code, 32); -} - -// not tested -void testChainCodeDerivation() -{ -#define TESTCASE(path_, expectedHex_) \ - { \ - uint32_t path[] = { UNWRAP path_ }; \ - testcase_deriveChainCode(path, ARRAY_LEN(path), expectedHex_); \ - } - - TESTCASE( - (HD + 44, HD + 1815, HD + 1), - "0b161cb11babe1f56c3f9f1cbbb7b6d2d13eeb3efa67205198a69b8d81885354" - ); - - TESTCASE( - (HD + 1852, HD + 1815, HD + 1, HD + 1, HD + 44), - "a92fb06ab6a4321d4b55878ec062988f315d9fe701009946cd95617dde8ba2a1" - ); - -#undef TESTCASE -} - - void run_key_derivation_test() { PRINTF("Running key derivation tests\n"); PRINTF("If they fail, make sure you seeded your device with\n"); PRINTF("12-word mnemonic: 11*abandon about\n"); - testPrivateKeyDerivation(); testPublicKeyDerivation(); - testChainCodeDerivation(); } #endif // DEVEL diff --git a/src/messageSigning.c b/src/messageSigning.c index a6aab51f..41e5c00d 100644 --- a/src/messageSigning.c +++ b/src/messageSigning.c @@ -2,66 +2,42 @@ #include "messageSigning.h" #include "cardano.h" -#include "keyDerivation.h" #include "bip44.h" - -static void signRawMessage(privateKey_t* privateKey, - const uint8_t* messageBuffer, size_t messageSize, - uint8_t* outBuffer, size_t outSize) -{ - uint8_t signature[64] = {0}; - ASSERT(messageSize < BUFFER_SIZE_PARANOIA); - ASSERT(outSize == SIZEOF(signature)); - - #ifndef FUZZING - // Note(ppershing): this could be done without - // temporary copy - STATIC_ASSERT(sizeof(int) == sizeof(size_t), "bad sizing"); - io_seproxyhal_io_heartbeat(); - size_t signatureSize = - (size_t) cx_eddsa_sign( - (const struct cx_ecfp_256_private_key_s*) privateKey, - 0 /* mode */, - CX_SHA512, - messageBuffer, messageSize, - NULL /* ctx */, 0 /* ctx len */, - signature, SIZEOF(signature), - 0 /* info */ - ); - io_seproxyhal_io_heartbeat(); - - ASSERT(signatureSize == ED25519_SIGNATURE_LENGTH); - memmove(outBuffer, signature, signatureSize); - #endif -} +#include "securityPolicy.h" +#include "crypto.h" static void signRawMessageWithPath(bip44_path_t* pathSpec, const uint8_t* messageBuffer, size_t messageSize, uint8_t* outBuffer, size_t outSize) { - ASSERT(messageSize < BUFFER_SIZE_PARANOIA); - ASSERT(outSize < BUFFER_SIZE_PARANOIA); + size_t sigLen = outSize; - chain_code_t chainCode; - privateKey_t privateKey; + ASSERT(messageSize < BUFFER_SIZE_PARANOIA); + ASSERT(sigLen == ED25519_SIGNATURE_LENGTH); - TRACE("derive private key"); + // Sanity check + ASSERT(pathSpec->length <= ARRAY_LEN(pathSpec->path)); - BEGIN_TRY { - TRY { - derivePrivateKey(pathSpec, &chainCode, &privateKey); + // if the path is invalid, it's a bug in previous validation + ASSERT(policyForDerivePrivateKey(pathSpec) != POLICY_DENY); - signRawMessage( - &privateKey, - messageBuffer, messageSize, - outBuffer, outSize - ); - } - FINALLY { - explicit_bzero(&privateKey, SIZEOF(privateKey)); - explicit_bzero(&chainCode, SIZEOF(chainCode)); + #ifndef FUZZING + { + cx_err_t error = crypto_eddsa_sign(pathSpec->path, + pathSpec->length, + messageBuffer, + messageSize, + outBuffer, + &sigLen); + if (error != CX_OK) { + PRINTF("error: %d", error); + ASSERT(false); } - } END_TRY; + } + #endif + + ASSERT(sigLen == ED25519_SIGNATURE_LENGTH); + } // sign the given hash by the private key derived according to the given path diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index 74904bb4..08adf0cc 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -529,7 +529,7 @@ void display_warning(const char* text, callback_t userAcceptCallback, } void display_choice(const char* text1, const char* text2, callback_t userAcceptCallback, - callback_t userRejectCallback) + callback_t userRejectCallback) { TRACE("Displaying choice"); From 4aa80a6e496da410230d7737e9266f82d6917f4c Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Wed, 16 Aug 2023 16:38:14 +0200 Subject: [PATCH 088/105] allow multidelegation keys --- src/bip44.c | 12 ++++++++---- src/bip44.h | 1 + src/securityPolicy.c | 3 +++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/bip44.c b/src/bip44.c index a65e2b96..9f6b62a9 100644 --- a/src/bip44.c +++ b/src/bip44.c @@ -218,7 +218,7 @@ static bool bip44_containsMoreThanAddress(const bip44_path_t* pathSpec) return (pathSpec->length > BIP44_I_ADDRESS + 1); } -// stake keys (one per account, should end with /2/0 after account) +// stake keys bool bip44_isOrdinaryStakingKeyPath(const bip44_path_t* pathSpec) { #define CHECK(cond) if (!(cond)) return false @@ -227,7 +227,7 @@ bool bip44_isOrdinaryStakingKeyPath(const bip44_path_t* pathSpec) CHECK(bip44_hasShelleyPrefix(pathSpec)); CHECK(isHardened(bip44_getAccount(pathSpec))); CHECK(bip44_getChainTypeValue(pathSpec) == CARDANO_CHAIN_STAKING_KEY); - CHECK(bip44_getAddressValue(pathSpec) == 0); // other values might be allowed in the future + CHECK(!isHardened(bip44_getAddressValue(pathSpec))); return true; #undef CHECK } @@ -246,6 +246,12 @@ bool bip44_isMultisigStakingKeyPath(const bip44_path_t* pathSpec) #undef CHECK } +bool bip44_isMultidelegationStakingKeyPath(const bip44_path_t* pathSpec) +{ + return (bip44_isOrdinaryStakingKeyPath(pathSpec) || bip44_isMultisigStakingKeyPath(pathSpec)) + && (bip44_getAddressValue(pathSpec) > 0); +} + bool bip44_isMintKeyPath(const bip44_path_t* pathSpec) { #define CHECK(cond) if (!(cond)) return false @@ -484,8 +490,6 @@ bool bip44_isPathReasonable(const bip44_path_t* pathSpec) case PATH_ORDINARY_STAKING_KEY: case PATH_MULTISIG_STAKING_KEY: - // we are checking the 5th item too (to avoid breaking this code - // if more than 1 stake key per account is allowed in the future) return bip44_hasReasonableAccount(pathSpec) && bip44_hasReasonableAddress(pathSpec); case PATH_MINT_KEY: diff --git a/src/bip44.h b/src/bip44.h index 75b882e4..f8629356 100644 --- a/src/bip44.h +++ b/src/bip44.h @@ -77,6 +77,7 @@ bool bip44_containsAddress(const bip44_path_t* pathSpec); bool bip44_isOrdinaryStakingKeyPath(const bip44_path_t* pathSpec); bool bip44_isMultisigStakingKeyPath(const bip44_path_t* pathSpec); +bool bip44_isMultidelegationStakingKeyPath(const bip44_path_t* pathSpec); bool bip44_isMintKeyPath(const bip44_path_t* pathSpec); diff --git a/src/securityPolicy.c b/src/securityPolicy.c index 91ec902c..ffb20d27 100644 --- a/src/securityPolicy.c +++ b/src/securityPolicy.c @@ -23,6 +23,9 @@ static inline bool is_standard_base_address(const addressParams_t* addressParams CHECK(bip44_classifyPath(&addressParams->stakingKeyPath) == PATH_ORDINARY_STAKING_KEY); CHECK(bip44_isPathReasonable(&addressParams->stakingKeyPath)); + // most SW wallets do not use multidelegation, + // so outputs sending funds to such addresses should not be hidden + CHECK(!bip44_isMultidelegationStakingKeyPath(&addressParams->stakingKeyPath)); CHECK( bip44_getAccount(&addressParams->stakingKeyPath) == From 186038026927489a4cff0dba7d50dbbca4a9453c Mon Sep 17 00:00:00 2001 From: Xavier Chapron Date: Wed, 27 Sep 2023 09:39:47 +0200 Subject: [PATCH 089/105] Bump version to 6.1.0 --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index c2748e4f..de1e6449 100644 --- a/Makefile +++ b/Makefile @@ -17,8 +17,8 @@ APPNAME = "Cardano ADA" APPVERSION_M = 6 -APPVERSION_N = 0 -APPVERSION_P = 9 +APPVERSION_N = 1 +APPVERSION_P = 0 APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" ifeq ($(BOLOS_SDK),) From 7dd0ea339a8e2d37a1fa63f1211582dd4d8c34d2 Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Mon, 25 Sep 2023 16:23:40 +0200 Subject: [PATCH 090/105] fix: memset --- src/crypto.c | 2 +- src/ipUtils.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index 92cfef08..fa79c5c4 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -15,7 +15,7 @@ * limitations under the License. *****************************************************************************/ #include // uint*_t -#include // memset, explicit_bzero +#include // explicit_bzero #include // bool #include "cx.h" diff --git a/src/ipUtils.c b/src/ipUtils.c index c0364037..7b6fc89f 100644 --- a/src/ipUtils.c +++ b/src/ipUtils.c @@ -84,7 +84,7 @@ void inet_ntop6 (const uint8_t* src, char* dst, size_t dstSize) * Copy the input (bytewise) array into a wordwise array. * Find the longest run of 0x00's in src[] for :: shorthanding. */ - memset(words, '\0', sizeof words); + explicit_bzero(words, sizeof words); for (int i = 0; i < NS_IN6ADDRSZ; i += 2) { ASSERT((unsigned int)(i / 2) < SIZEOF(words)); words[i / 2] = (src[i] << 8) | src[i + 1]; From ca899d57ccdab6a13dd5067ec9e2c9c93b32a3fd Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Mon, 25 Sep 2023 16:31:20 +0200 Subject: [PATCH 091/105] fix: protocol magic --- src/addressUtilsByron.c | 3 ++- src/cbor.c | 1 - src/signTxOutput.h | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/addressUtilsByron.c b/src/addressUtilsByron.c index c621535c..078706e8 100644 --- a/src/addressUtilsByron.c +++ b/src/addressUtilsByron.c @@ -175,7 +175,7 @@ uint32_t extractProtocolMagic( read_view_t view = make_read_view(addressBuffer, addressBuffer + addressSize); - uint32_t protocolMagic; + uint32_t protocolMagic = MAINNET_PROTOCOL_MAGIC; // mainnet addresses do not contain protocol magic bool protocolMagicFound = false; { const uint8_t* unboxedAddressPayload; @@ -245,6 +245,7 @@ uint32_t extractProtocolMagic( VALIDATE(view_remainingSize(&view) == 0, ERR_INVALID_DATA); if (!protocolMagicFound) { + // mainnet addresses are not supposed to explicitly contain protocol magic at all protocolMagic = MAINNET_PROTOCOL_MAGIC; } diff --git a/src/cbor.c b/src/cbor.c index 2ee4721a..96aafa6c 100644 --- a/src/cbor.c +++ b/src/cbor.c @@ -46,7 +46,6 @@ cbor_token_t cbor_parseToken(const uint8_t* buf, size_t size) if (val < 24) { result.width = 0; result.value = val; - // return result; } else { // shift buffer // Holds minimum value for a given byte-width. diff --git a/src/signTxOutput.h b/src/signTxOutput.h index 5439bd62..0d049108 100644 --- a/src/signTxOutput.h +++ b/src/signTxOutput.h @@ -35,7 +35,6 @@ typedef enum { typedef struct { sign_tx_output_state_t state; int ui_step; -// void (*ui_advanceState)(); const char* ui_text1; const char* ui_text2; const char* ui_text3; From dcf057cc37265014426dbfc7eaaadcf252db5cd6 Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Mon, 25 Sep 2023 16:40:21 +0200 Subject: [PATCH 092/105] fix: security policies --- src/securityPolicy.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/securityPolicy.c b/src/securityPolicy.c index ffb20d27..a694a749 100644 --- a/src/securityPolicy.c +++ b/src/securityPolicy.c @@ -1790,7 +1790,6 @@ security_policy_t policyForCVoteRegistrationStakingKey( } // based on https://input-output-rnd.slack.com/archives/C036XSMFXE3/p1668185230182239 -// TODO make sure this is what we want security_policy_t policyForCVoteRegistrationPaymentDestination( const tx_output_destination_storage_t* destination, const uint8_t networkId From 206cb6691c05883d243e8d977b0e9edd06d72156 Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Mon, 25 Sep 2023 16:46:16 +0200 Subject: [PATCH 093/105] fix: remove double if --- src/signTxCVoteRegistration.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/signTxCVoteRegistration.c b/src/signTxCVoteRegistration.c index 63d288b9..cb06ffb5 100644 --- a/src/signTxCVoteRegistration.c +++ b/src/signTxCVoteRegistration.c @@ -604,11 +604,9 @@ static void signTxCVoteRegistration_handleVotingPurposeAPDU(const uint8_t* wireD VALIDATE(subctx->format == CIP36, ERR_INVALID_DATA); } - if (isVotingPurposeIncluded) { - subctx->stateData.votingPurpose = parse_u8be(&view); - } else { - subctx->stateData.votingPurpose = DEFAULT_VOTING_PURPOSE; - } + subctx->stateData.votingPurpose = (isVotingPurposeIncluded) ? + parse_u8be(&view) : + DEFAULT_VOTING_PURPOSE; TRACE("votingPurpose = %u", subctx->stateData.votingPurpose); VALIDATE(view_remainingSize(&view) == 0, ERR_INVALID_DATA); From a71415a6e24d8aa491f2fa91daf9f352a4956071 Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Mon, 25 Sep 2023 17:03:26 +0200 Subject: [PATCH 094/105] fix: appFlags --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index de1e6449..80819cb4 100644 --- a/Makefile +++ b/Makefile @@ -174,7 +174,7 @@ NANOS_ID = 1 WORDS = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" PIN = 5555 -APP_LOAD_PARAMS =--appFlags 0x240 --curve ed25519 --path "44'/1815'" --path "1852'/1815'" --path "1853'/1815'" --path "1854'/1815'" --path "1855'/1815'" --path "1694'/1815'" +APP_LOAD_PARAMS =--appFlags 0x200 --curve ed25519 --path "44'/1815'" --path "1852'/1815'" --path "1853'/1815'" --path "1854'/1815'" --path "1855'/1815'" --path "1694'/1815'" APP_LOAD_PARAMS += $(COMMON_LOAD_PARAMS) load: From 495663457e5a9d3830a5715aa4b3e7a2ebd238d9 Mon Sep 17 00:00:00 2001 From: Jan Mazak Date: Thu, 5 Oct 2023 20:18:57 +0200 Subject: [PATCH 095/105] bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 80819cb4..186947d2 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ APPNAME = "Cardano ADA" APPVERSION_M = 6 APPVERSION_N = 1 -APPVERSION_P = 0 +APPVERSION_P = 1 APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" ifeq ($(BOLOS_SDK),) From c04d29691db8c1723d0a0ba26e75eeb375b38855 Mon Sep 17 00:00:00 2001 From: Jorge Martins Date: Fri, 13 Oct 2023 16:53:48 +0200 Subject: [PATCH 096/105] update yhql and integrate with clusterfuzzlite CI 5 min on every PR and 5 minute every Saturday --- .clusterfuzzlite/Dockerfile | 7 + .clusterfuzzlite/build.sh | 9 + .clusterfuzzlite/project.yaml | 1 + .github/workflows/cflite_cron.yml | 41 +++++ .github/workflows/cflite_pr.yml | 43 +++++ fuzz/CMakeLists.txt | 115 ------------ fuzz/coverage.py | 79 -------- fuzz/fuzztest.c | 69 ------- fuzz/glyphs.c | 8 - fuzz/glyphs.h | 10 - fuzz/os_mocks.c | 44 ----- fuzz/readme.md | 42 ----- fuzzing/CMakeLists.txt | 171 ++++++++++++++++++ fuzzing/README.md | 39 ++++ .../corpus}/signOperationalCertificate | Bin .../corpus}/signTxOrdinaryMary0 | Bin .../corpus}/signTxOrdinaryMary1 | Bin .../corpus}/signTxOrdinaryMary2 | Bin .../corpus}/signTxOrdinaryMary3 | Bin .../corpus}/signTxOrdinaryMary4 | Bin .../corpus}/signTxOrdinaryMary5 | Bin .../corpus}/signTxOrdinaryMary6 | Bin .../corpus}/signTxPoolRegistrationOKOperator0 | Bin .../corpus}/signTxPoolRegistrationOKOperator1 | Bin .../corpus}/signTxPoolRegistrationOKOperator2 | Bin .../corpus}/signTxPoolRegistrationOKOwner0 | Bin .../corpus}/signTxPoolRegistrationOKOwner1 | Bin .../corpus}/signTxPoolRegistrationOKOwner2 | Bin .../corpus}/signTxPoolRegistrationOKOwner3 | Bin .../corpus}/signTxPoolRegistrationOKOwner4 | Bin .../corpus}/signTxPoolRegistrationOKOwner5 | Bin .../corpus}/signTxPoolRegistrationOKOwner6 | Bin .../corpus}/signTxPoolRegistrationOKOwner7 | Bin .../corpus}/signTxPoolRegistrationOKOwner8 | Bin {fuzz/ref_corpus => fuzzing/corpus}/signtx | Bin fuzzing/include/glyphs.h | 12 ++ fuzzing/include/harness.h | 0 fuzzing/src/all_harness.c | 58 ++++++ fuzzing/src/deriveAddress_harness.c | 53 ++++++ fuzzing/src/deriveNativeScriptHash_harness.c | 52 ++++++ fuzzing/src/getPublicKeys_harness.c | 52 ++++++ fuzzing/src/glyphs.c | 12 ++ fuzzing/src/os_mocks.c | 101 +++++++++++ fuzzing/src/signCVote_harness.c | 52 ++++++ fuzzing/src/signOpCert_harness.c | 52 ++++++ fuzzing/src/signTx_harness.c | 52 ++++++ src/bip44.c | 6 +- src/uiHelpers.h | 2 +- src/uiScreens_bagl.c | 2 + src/utils.h | 4 + 50 files changed, 817 insertions(+), 371 deletions(-) create mode 100644 .clusterfuzzlite/Dockerfile create mode 100644 .clusterfuzzlite/build.sh create mode 100644 .clusterfuzzlite/project.yaml create mode 100644 .github/workflows/cflite_cron.yml create mode 100644 .github/workflows/cflite_pr.yml delete mode 100644 fuzz/CMakeLists.txt delete mode 100644 fuzz/coverage.py delete mode 100644 fuzz/fuzztest.c delete mode 100644 fuzz/glyphs.c delete mode 100644 fuzz/glyphs.h delete mode 100644 fuzz/os_mocks.c delete mode 100644 fuzz/readme.md create mode 100644 fuzzing/CMakeLists.txt create mode 100644 fuzzing/README.md rename {fuzz/ref_corpus => fuzzing/corpus}/signOperationalCertificate (100%) rename {fuzz/ref_corpus => fuzzing/corpus}/signTxOrdinaryMary0 (100%) rename {fuzz/ref_corpus => fuzzing/corpus}/signTxOrdinaryMary1 (100%) rename {fuzz/ref_corpus => fuzzing/corpus}/signTxOrdinaryMary2 (100%) rename {fuzz/ref_corpus => fuzzing/corpus}/signTxOrdinaryMary3 (100%) rename {fuzz/ref_corpus => fuzzing/corpus}/signTxOrdinaryMary4 (100%) rename {fuzz/ref_corpus => fuzzing/corpus}/signTxOrdinaryMary5 (100%) rename {fuzz/ref_corpus => fuzzing/corpus}/signTxOrdinaryMary6 (100%) rename {fuzz/ref_corpus => fuzzing/corpus}/signTxPoolRegistrationOKOperator0 (100%) rename {fuzz/ref_corpus => fuzzing/corpus}/signTxPoolRegistrationOKOperator1 (100%) rename {fuzz/ref_corpus => fuzzing/corpus}/signTxPoolRegistrationOKOperator2 (100%) rename {fuzz/ref_corpus => fuzzing/corpus}/signTxPoolRegistrationOKOwner0 (100%) rename {fuzz/ref_corpus => fuzzing/corpus}/signTxPoolRegistrationOKOwner1 (100%) rename {fuzz/ref_corpus => fuzzing/corpus}/signTxPoolRegistrationOKOwner2 (100%) rename {fuzz/ref_corpus => fuzzing/corpus}/signTxPoolRegistrationOKOwner3 (100%) rename {fuzz/ref_corpus => fuzzing/corpus}/signTxPoolRegistrationOKOwner4 (100%) rename {fuzz/ref_corpus => fuzzing/corpus}/signTxPoolRegistrationOKOwner5 (100%) rename {fuzz/ref_corpus => fuzzing/corpus}/signTxPoolRegistrationOKOwner6 (100%) rename {fuzz/ref_corpus => fuzzing/corpus}/signTxPoolRegistrationOKOwner7 (100%) rename {fuzz/ref_corpus => fuzzing/corpus}/signTxPoolRegistrationOKOwner8 (100%) rename {fuzz/ref_corpus => fuzzing/corpus}/signtx (100%) create mode 100644 fuzzing/include/glyphs.h create mode 100644 fuzzing/include/harness.h create mode 100644 fuzzing/src/all_harness.c create mode 100644 fuzzing/src/deriveAddress_harness.c create mode 100644 fuzzing/src/deriveNativeScriptHash_harness.c create mode 100644 fuzzing/src/getPublicKeys_harness.c create mode 100644 fuzzing/src/glyphs.c create mode 100644 fuzzing/src/os_mocks.c create mode 100644 fuzzing/src/signCVote_harness.c create mode 100644 fuzzing/src/signOpCert_harness.c create mode 100644 fuzzing/src/signTx_harness.c diff --git a/.clusterfuzzlite/Dockerfile b/.clusterfuzzlite/Dockerfile new file mode 100644 index 00000000..6f2d35d9 --- /dev/null +++ b/.clusterfuzzlite/Dockerfile @@ -0,0 +1,7 @@ +FROM ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest AS LITE_BUILDER + +FROM gcr.io/oss-fuzz-base/base-builder:v1 +COPY . $SRC/app-cardano +COPY ./.clusterfuzzlite/build.sh $SRC/ +COPY --from=LITE_BUILDER /opt/ledger-secure-sdk $SRC/app-cardano/BOLOS_SDK +WORKDIR $SRC/app-cardano \ No newline at end of file diff --git a/.clusterfuzzlite/build.sh b/.clusterfuzzlite/build.sh new file mode 100644 index 00000000..6bf7a52e --- /dev/null +++ b/.clusterfuzzlite/build.sh @@ -0,0 +1,9 @@ +#!/bin/bash -eu + +# build fuzzers + +pushd fuzzing +cmake -DBOLOS_SDK=../BOLOS_SDK -Bbuild -H. +make -C build VERBOSE=1 +mv build/*_harness $OUT +popd \ No newline at end of file diff --git a/.clusterfuzzlite/project.yaml b/.clusterfuzzlite/project.yaml new file mode 100644 index 00000000..e196c5cc --- /dev/null +++ b/.clusterfuzzlite/project.yaml @@ -0,0 +1 @@ +language: c \ No newline at end of file diff --git a/.github/workflows/cflite_cron.yml b/.github/workflows/cflite_cron.yml new file mode 100644 index 00000000..44ac10c2 --- /dev/null +++ b/.github/workflows/cflite_cron.yml @@ -0,0 +1,41 @@ +name: ClusterFuzzLite cron tasks +on: + workflow_dispatch: + push: + branches: + - main # Use your actual default branch here. + schedule: + - cron: '0 13 * * 6' # At 01:00 PM, only on Saturday +permissions: read-all +jobs: + Fuzzing: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - mode: batch + sanitizer: address + - mode: batch + sanitizer: memory + - mode: prune + sanitizer: address + - mode: coverage + sanitizer: coverage + steps: + - name: Build Fuzzers (${{ matrix.mode }} - ${{ matrix.sanitizer }}) + id: build + uses: google/clusterfuzzlite/actions/build_fuzzers@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + language: c # Change this to the language you are fuzzing. + sanitizer: ${{ matrix.sanitizer }} + - name: Run Fuzzers (${{ matrix.mode }} - ${{ matrix.sanitizer }}) + id: run + uses: google/clusterfuzzlite/actions/run_fuzzers@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + fuzz-seconds: 300 # 5 minutes + mode: ${{ matrix.mode }} + sanitizer: ${{ matrix.sanitizer }} + \ No newline at end of file diff --git a/.github/workflows/cflite_pr.yml b/.github/workflows/cflite_pr.yml new file mode 100644 index 00000000..f70175e1 --- /dev/null +++ b/.github/workflows/cflite_pr.yml @@ -0,0 +1,43 @@ +name: ClusterFuzzLite PR fuzzing +on: + pull_request: + paths: + - '**' +permissions: read-all +jobs: + PR: + runs-on: ubuntu-latest + concurrency: + group: ${{ github.workflow }}-${{ matrix.sanitizer }}-${{ github.ref }} + cancel-in-progress: true + strategy: + fail-fast: false + matrix: + sanitizer: [address, undefined, memory] # Override this with the sanitizers you want. + steps: + - name: Build Fuzzers (${{ matrix.sanitizer }}) + id: build + uses: google/clusterfuzzlite/actions/build_fuzzers@v1 + with: + language: c # Change this to the language you are fuzzing. + github-token: ${{ secrets.GITHUB_TOKEN }} + sanitizer: ${{ matrix.sanitizer }} + # Optional but recommended: used to only run fuzzers that are affected + # by the PR. + # storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/OWNER/STORAGE-REPO-NAME.git + # storage-repo-branch: main # Optional. Defaults to "main" + # storage-repo-branch-coverage: gh-pages # Optional. Defaults to "gh-pages". + - name: Run Fuzzers (${{ matrix.sanitizer }}) + id: run + uses: google/clusterfuzzlite/actions/run_fuzzers@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + fuzz-seconds: 300 # 5 minutes + mode: 'code-change' + sanitizer: ${{ matrix.sanitizer }} + output-sarif: true + # Optional but recommended: used to download the corpus produced by + # batch fuzzing. + # storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/OWNER/STORAGE-REPO-NAME.git + # storage-repo-branch: main # Optional. Defaults to "main" + # storage-repo-branch-coverage: gh-pages # Optional. Defaults to "gh-pages". \ No newline at end of file diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt deleted file mode 100644 index e57620c5..00000000 --- a/fuzz/CMakeLists.txt +++ /dev/null @@ -1,115 +0,0 @@ -cmake_minimum_required(VERSION 3.10) - -project(cardano_fuzzer C) - -set(CMAKE_C_STANDARD 11) - -set (SDK_PATH $ENV{BOLOS_SDK}) - -include_directories(. ../src) -include_directories( - ${SDK_PATH}/include/ - ${SDK_PATH}/lib_cxng/include/ - ${SDK_PATH}/lib_cxng/src/ - ${SDK_PATH}/lib_ux/include/ - ) - -add_compile_options(-g -ggdb2) -if (FUZZ) -add_compile_options(-O3) -add_compile_options(-fsanitize=fuzzer,address) -add_link_options(-fsanitize=fuzzer,address) -add_compile_definitions(HAVE_PRINTF PRINTF=printf) -endif() - -add_compile_definitions( - FUZZING - OS_IO_SEPROXYHAL - IO_SEPROXYHAL_BUFFER_SIZE_B=300 - IO_HID_EP_LENGTH=64 - HAVE_UX_FLOW - HAVE_BAGL - APPVERSION="0.0.0" -) - -# hack so that core_sc000.h compiles -if (WIN32) -add_compile_definitions(__GNUC__) -endif() - -add_compile_definitions( - HAVE_ECC - HAVE_ECC_WEIERSTRASS - HAVE_SECP256K1_CURVE - HAVE_SECP256R1_CURVE - HAVE_ECC_TWISTED_EDWARDS - HAVE_ED25519_CURVE - HAVE_ECDSA - HAVE_EDDSA - HAVE_HASH - HAVE_SHA256 - HAVE_SHA3 - HAVE_BLAKE2 -) - -set(LIBUX_PATH ${SDK_PATH}/lib_ux) - -set (LIBUX_SRCS - ${LIBUX_PATH}/src/ux_flow_engine.c - ${LIBUX_PATH}/src/ux_layout_bb.c - ${LIBUX_PATH}/src/ux_layout_bn.c - ${LIBUX_PATH}/src/ux_layout_bnn.c - ${LIBUX_PATH}/src/ux_layout_bnnn.c - ${LIBUX_PATH}/src/ux_layout_nn.c - ${LIBUX_PATH}/src/ux_layout_paging.c - ${LIBUX_PATH}/src/ux_layout_paging_compute.c - ${LIBUX_PATH}/src/ux_layout_pbb.c - ${LIBUX_PATH}/src/ux_layout_pn.c - ${LIBUX_PATH}/src/ux_layout_pnn.c - ${LIBUX_PATH}/src/ux_layout_utils.c - ${LIBUX_PATH}/src/ux_stack.c -) - -set(SOURCES - fuzztest.c - os_mocks.c - glyphs.c - - ../src/addressUtilsByron.c - ../src/addressUtilsShelley.c - ../src/assert.c - ../src/auxDataHashBuilder.c - ../src/base58.c - ../src/bech32.c - ../src/bip44.c - ../src/cardano.c - ../src/cbor.c - ../src/crc32.c - ../src/io.c - ../src/ipUtils.c - ../src/keyDerivation.c - ../src/hexUtils.c - ../src/messageSigning.c - ../src/securityPolicy.c - ../src/signOpCert.c - ../src/signTx.c - ../src/signTxOutput.c - ../src/state.c - ../src/signTxPoolRegistration.c - ../src/signTxCVoteRegistration.c - ../src/signTxUtils.c - ../src/textUtils.c - ../src/txHashBuilder.c - ../src/uiHelpers.c - ../src/uiHelpers_nanox.c - ../src/uiScreens.c - ../src/getPublicKeys.c - ${LIBUX_SRCS}) - -add_executable(fuzzer ${SOURCES}) -add_executable(fuzzer_coverage ${SOURCES}) - -target_compile_options(fuzzer_coverage PRIVATE -fprofile-instr-generate -fcoverage-mapping) - -target_link_options(fuzzer PRIVATE) -target_link_options(fuzzer_coverage PRIVATE) \ No newline at end of file diff --git a/fuzz/coverage.py b/fuzz/coverage.py deleted file mode 100644 index de47f195..00000000 --- a/fuzz/coverage.py +++ /dev/null @@ -1,79 +0,0 @@ -import os -import platform -import subprocess -from glob import glob - - -def extract_profiles(corpus_path, cov_executable): - """ Run corpus through coverage executable. This function - avoids a limitation on filename length on Windows """ - # group by packs of N for faster execution - # N has to be low enough that Windows does not - # complain about too long filenames. 512 seems fine. - file_list = glob(os.path.join(corpus_path, "*")) - N = 512 - for p in range(0, len(file_list), N): - subprocess.run([cov_executable, "-close_fd_mask=1", *file_list[p : p + N]]) - - -def merge_profile_data(): - """ Merge profiling data """ - print( - subprocess.run( - [ - "llvm-profdata", - "merge", - "-sparse", - "*.profraw", - "-o", - "default.profdata", - ], - check=True, - ) - ) - - -def show_summary(cov_executable): - """ Displays the main report from llvm-cov """ - print( - subprocess.run( - ["llvm-cov", "report", "--instr-profile=default.profdata", cov_executable] - ) - ) - - -def create_report(cov_executable): - """ Create a report in HTML format into 'coverage/index.html' """ - print( - subprocess.run( - [ - "llvm-cov", - "show", - cov_executable, - "--instr-profile=default.profdata", - "--format=html", - "-o", - "./coverage/", - ] - ) - ) - - -if __name__ == "__main__": - from argparse import ArgumentParser - - argp = ArgumentParser() - argp.add_argument("-path", default="./build/", help="Path to build directory") - args = argp.parse_args() - - cov = os.path.join( - args.path, "fuzzer_coverage" + ".exe" * (platform.system() == "Windows") - ) - - if not os.path.exists(cov): - raise Exception(f"Fuzzer executable ({cov}) cannot be found") - - extract_profiles("./corpus/", cov) - merge_profile_data() - show_summary(cov) - create_report(cov) diff --git a/fuzz/fuzztest.c b/fuzz/fuzztest.c deleted file mode 100644 index 26dd80e9..00000000 --- a/fuzz/fuzztest.c +++ /dev/null @@ -1,69 +0,0 @@ -#include -#include -#include "cx.h" - -#include "signTx.h" -#include "getPublicKeys.h" - -ux_state_t G_ux; -uint8_t G_io_apdu_buffer[IO_APDU_BUFFER_SIZE]; - -#ifdef DEVEL -#include "utils.h" -unsigned int app_stack_canary = APP_STACK_CANARY_MAGIC; -#endif - -void signTx_handleAPDU_no_throw(uint8_t p1, uint8_t p2, const uint8_t *wireBuffer, size_t wireSize, bool isNewCall) { - BEGIN_TRY { - TRY { - signTx_handleAPDU(p1, p2, wireBuffer, wireSize, isNewCall); - } - CATCH_ALL { - } - FINALLY { - } - } END_TRY; -} - -void signOpCert_handleAPDU_no_throw(uint8_t p1, uint8_t p2, const uint8_t *wireBuffer, size_t wireSize, bool isNewCall) { - BEGIN_TRY { - TRY { - signOpCert_handleAPDU(p1, p2, wireBuffer, wireSize, isNewCall); - } - CATCH_ALL { - } - FINALLY { - } - } END_TRY; -} - -int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - - UX_INIT(); - - bool is_first = true; - uint8_t * input = Data; - size_t size = Size; - while ((size > 5) && (input[3] < size-4)) { - io_state = IO_EXPECT_NONE; - uint8_t ins = input[0]; - uint8_t p1 = input[1]; - uint8_t p2 = input[2]; - uint8_t lc = input[3]; - - switch (ins) { - case 0x22: - signOpCert_handleAPDU_no_throw(p1, p2, &input[4], lc, is_first); - break; - case 0x21: - signTx_handleAPDU_no_throw(p1, p2, &input[4], lc, is_first); - break; - default: - return 0; - } - is_first = false; - size -= lc + 4; - input += lc + 4; - } - return 0; -} \ No newline at end of file diff --git a/fuzz/glyphs.c b/fuzz/glyphs.c deleted file mode 100644 index 0cc6f916..00000000 --- a/fuzz/glyphs.c +++ /dev/null @@ -1,8 +0,0 @@ -#include - -const uint8_t C_icon_crossmark[1] = {0}; -const uint8_t C_icon_loader[1] = {0}; -const uint8_t C_icon_eye[1] = {0}; -const uint8_t C_icon_validate_14[1] = {0}; -const uint8_t C_icon_left[1] = {0}; -const uint8_t C_icon_right[1] = {0}; diff --git a/fuzz/glyphs.h b/fuzz/glyphs.h deleted file mode 100644 index 0a6fe956..00000000 --- a/fuzz/glyphs.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include - -extern const uint8_t C_icon_crossmark[1]; -extern const uint8_t C_icon_loader[1]; -extern const uint8_t C_icon_eye[1]; -extern const uint8_t C_icon_validate_14[1]; -extern const uint8_t C_icon_left[1]; -extern const uint8_t C_icon_right[1]; diff --git a/fuzz/os_mocks.c b/fuzz/os_mocks.c deleted file mode 100644 index 2e071eeb..00000000 --- a/fuzz/os_mocks.c +++ /dev/null @@ -1,44 +0,0 @@ -#include "os.h" -#include "cx.h" -#include "ux.h" - -void os_longjmp(unsigned int exception) { - longjmp(try_context_get()->jmp_buf, exception); -} - -try_context_t *current_context = NULL; -try_context_t *try_context_get(void) { - return current_context; -} - -try_context_t *try_context_set(try_context_t *ctx) { - try_context_t *previous_ctx = current_context; - current_context = ctx; - return previous_ctx; -} - -bolos_task_status_t os_sched_last_status(unsigned int task_idx) {return 1;}; -unsigned short io_exchange(unsigned char chan, unsigned short tx_len) {return 0;}; -void * pic(void * linked_addr) {return linked_addr;} - -void io_seproxyhal_display_default(const bagl_element_t * bagl) { - if (bagl->text) { - printf("[-] %s\n", bagl->text); - } -} - -void ui_idle() {}; - -unsigned int os_ux(bolos_ux_params_t * params) {return 0;}; -void io_seproxyhal_init_ux(void) {}; -unsigned int io_seph_is_status_sent (void) {return 0;}; -bolos_bool_t os_perso_isonboarded(void) {return (bolos_bool_t)BOLOS_UX_OK;}; -void io_seproxyhal_general_status(void) {}; -void io_seph_send(const unsigned char * buffer, unsigned short length) {}; -unsigned short io_seph_recv ( unsigned char * buffer, unsigned short maxlength, unsigned int flags ) {return 0;}; -void halt() { for(;;); }; -bolos_bool_t os_global_pin_is_validated(void) {return (bolos_bool_t)BOLOS_UX_OK;}; -cx_err_t cx_hash_no_throw(cx_hash_t *hash, uint32_t mode, const uint8_t *in, size_t len, uint8_t *out, size_t out_len) { return 0;}; -size_t cx_hash_get_size(const cx_hash_t *ctx) { return 32;}; -cx_err_t cx_blake2b_init_no_throw(cx_blake2b_t *hash, size_t size) {return 0;}; -cx_err_t cx_sha3_init_no_throw(cx_sha3_t *hash, size_t size) {return 0;}; diff --git a/fuzz/readme.md b/fuzz/readme.md deleted file mode 100644 index d1a360da..00000000 --- a/fuzz/readme.md +++ /dev/null @@ -1,42 +0,0 @@ -# Cardano Fuzzer - -## Building and fuzzing - -### Linux - -```shell -BOLOS_SDK=/path/to/sdk/ cmake -Bbuild -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DFUZZ=1 -cd build -make -``` - -```shell -mkdir ../corpus -cp ../ref_corpus/* ../corpus/ -./fuzzer ../corpus/ -close_fd_mask=1 -``` - -### Windows - -```shell -$env:BOLOS_SDK = 'C:/path/to/sdk' # (PowerShell) -cmake -Bbuild -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DFUZZ=1 -cd build -ninja -``` - -```shell -mkdir ../corpus -copy ../ref_corpus/valid_tx ../corpus/valid_tx -./fuzzer.exe ../corpus/ -close_fd_mask=1 -``` - -## Coverage information - -Generating coverage: - -``` -python3 coverage.py -``` - -Will output an HTML report in `./coverage/index.html`. \ No newline at end of file diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt new file mode 100644 index 00000000..cbc810f7 --- /dev/null +++ b/fuzzing/CMakeLists.txt @@ -0,0 +1,171 @@ +cmake_minimum_required(VERSION 3.22) + +project(cardano_fuzzers C) + +set(CMAKE_C_STANDARD 11) + +if (NOT CMAKE_C_COMPILER_ID MATCHES "Clang") + message(FATAL_ERROR "Fuzzer needs to be built with Clang") +endif() + +# guard against in-source builds +if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) + message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt. ") +endif() + + +if (NOT DEFINED ENV{LIB_FUZZING_ENGINE}) + add_compile_options(-fsanitize=address,fuzzer-no-link) + add_link_options(-fsanitize=address,fuzzer) +else() + add_link_options($ENV{LIB_FUZZING_ENGINE}) +endif() + + + +set(SDK_PATH ${BOLOS_SDK}) +set(UX_PATH ${SDK_PATH}/lib_ux) +set(CARDANO_PATH ..) + +set(UX_SOURCE + ${UX_PATH}/src/ux_flow_engine.c + ${UX_PATH}/src/ux_layout_bb.c + ${UX_PATH}/src/ux_layout_bn.c + ${UX_PATH}/src/ux_layout_bnn.c + ${UX_PATH}/src/ux_layout_bnnn.c + ${UX_PATH}/src/ux_layout_nn.c + ${UX_PATH}/src/ux_layout_paging.c + ${UX_PATH}/src/ux_layout_paging_compute.c + ${UX_PATH}/src/ux_layout_pbb.c + ${UX_PATH}/src/ux_layout_pb.c + ${UX_PATH}/src/ux_layout_pn.c + ${UX_PATH}/src/ux_layout_pnn.c + ${UX_PATH}/src/ux_layout_utils.c + ${UX_PATH}/src/ux_stack.c +) + +set(CARDANO_SOURCE + ${CARDANO_PATH}/src/addressUtilsByron.c + ${CARDANO_PATH}/src/addressUtilsShelley.c + ${CARDANO_PATH}/src/app_mode.c + ${CARDANO_PATH}/src/assert.c + ${CARDANO_PATH}/src/auxDataHashBuilder.c + ${CARDANO_PATH}/src/base58.c + ${CARDANO_PATH}/src/bech32.c + ${CARDANO_PATH}/src/bip44.c + ${CARDANO_PATH}/src/cardano.c + ${CARDANO_PATH}/src/cbor.c + ${CARDANO_PATH}/src/crc32.c + ${CARDANO_PATH}/src/crypto.c + ${CARDANO_PATH}/src/deriveAddress.c + ${CARDANO_PATH}/src/deriveNativeScriptHash.c + ${CARDANO_PATH}/src/deriveNativeScriptHash_ui.c + ${CARDANO_PATH}/src/getPublicKeys.c + ${CARDANO_PATH}/src/getPublicKeys_ui.c + ${CARDANO_PATH}/src/getSerial.c + ${CARDANO_PATH}/src/getVersion.c + ${CARDANO_PATH}/src/handlers.c + ${CARDANO_PATH}/src/hexUtils.c + ${CARDANO_PATH}/src/io.c + ${CARDANO_PATH}/src/ipUtils.c + ${CARDANO_PATH}/src/keyDerivation.c + # ${CARDANO_PATH}/src/menu_nanos.c + ${CARDANO_PATH}/src/menu_nanox.c + ${CARDANO_PATH}/src/messageSigning.c + ${CARDANO_PATH}/src/nativeScriptHashBuilder.c + ${CARDANO_PATH}/src/runTests.c + ${CARDANO_PATH}/src/securityPolicy.c + ${CARDANO_PATH}/src/signCVote.c + ${CARDANO_PATH}/src/signCVote_ui.c + ${CARDANO_PATH}/src/signOpCert.c + ${CARDANO_PATH}/src/signTx.c + ${CARDANO_PATH}/src/signTxCVoteRegistration.c + ${CARDANO_PATH}/src/signTxCVoteRegistration_ui.c + ${CARDANO_PATH}/src/signTxMint.c + ${CARDANO_PATH}/src/signTxMint_ui.c + ${CARDANO_PATH}/src/signTxOutput.c + ${CARDANO_PATH}/src/signTxOutput_ui.c + ${CARDANO_PATH}/src/signTxPoolRegistration.c + ${CARDANO_PATH}/src/signTxPoolRegistration_ui.c + ${CARDANO_PATH}/src/signTx_ui.c + ${CARDANO_PATH}/src/signTxUtils.c + ${CARDANO_PATH}/src/state.c + ${CARDANO_PATH}/src/textUtils.c + ${CARDANO_PATH}/src/tokens.c + ${CARDANO_PATH}/src/txHashBuilder.c + ${CARDANO_PATH}/src/uiHelpers.c + ${CARDANO_PATH}/src/uiHelpers_nanos.c + ${CARDANO_PATH}/src/uiHelpers_nanox.c + ${CARDANO_PATH}/src/ui_menu_nbgl.c + ${CARDANO_PATH}/src/ui_nbgl.c + ${CARDANO_PATH}/src/uiScreens_bagl.c + ${CARDANO_PATH}/src/uiScreens_nbgl.c + ${CARDANO_PATH}/src/votecastHashBuilder.c +) + +include_directories( + ${BOLOS_SDK}/include + ${BOLOS_SDK}/target/nanox/include + ${BOLOS_SDK}/lib_cxng/include + ${BOLOS_SDK}/lib_bagl/include + ${BOLOS_SDK}/lib_ux/include + + ${CARDANO_PATH}/src + ./include +) + +add_compile_definitions( + FUZZING + HAVE_BAGL + BAGL_WIDTH=128 + BAGL_HEIGHT=64 + HAVE_UX_FLOW + + MAJOR_VERSION=1 + MINOR_VERSION=1 + PATCH_VERSION=1 + APPVERSION=\"1.1.1\" + + IO_HID_EP_LENGTH=64 + IO_SEPROXYHAL_BUFFER_SIZE_B=300 + OS_IO_SEPROXYHAL + + HAVE_ECC + HAVE_BLAKE2 + HAVE_ECC_WEIERSTRASS + HAVE_SECP256K1_CURVE + HAVE_SECP256R1_CURVE + HAVE_ECC_TWISTED_EDWARDS + HAVE_ED25519_CURVE + HAVE_ECDSA + HAVE_EDDSA + HAVE_HASH + HAVE_SHA256 + HAVE_SHA3 +) + +set(SOURCE + ${UX_SOURCE} + ${CARDANO_SOURCE} + ./src/os_mocks.c + ./src/glyphs.c +) + + + +set(harnesses + all_harness + deriveAddress_harness + deriveNativeScriptHash_harness + getPublicKeys_harness + signCVote_harness + signOpCert_harness + signTx_harness +) + +foreach(harness IN LISTS harnesses) + add_executable(${harness} + ./src/${harness}.c + ${SOURCE} + ) +endforeach() \ No newline at end of file diff --git a/fuzzing/README.md b/fuzzing/README.md new file mode 100644 index 00000000..a4688c84 --- /dev/null +++ b/fuzzing/README.md @@ -0,0 +1,39 @@ +## Compilation + +In `fuzzing` folder + +``` +cmake -DBOLOS_SDK=/path/to/sdk -DCMAKE_C_COMPILER=/usr/bin/clang -Bbuild -H. +``` + +then + +``` +make -C build +``` + +Harnesses built: +``` +all_harness +deriveAddress_harness +deriveNativeScriptHash_harness +getPublicKeys_harness +signCVote_harness +signOpCert_harness +signTx_harness +``` + +## Run + +To start fuzzing simply do `./build/` where `` is one of the files above. For instance + +``` +./build/deriveAddress_harness +``` + +Since there is an already existing corpus, to start fuzzing with it simply do `./build/ ./corpus` + + + +## Notes +For more context regarding fuzzing check out the app-boilerplate fuzzing [README.md](https://github.com/LedgerHQ/app-boilerplate/blob/master/fuzzing/README.md) diff --git a/fuzz/ref_corpus/signOperationalCertificate b/fuzzing/corpus/signOperationalCertificate similarity index 100% rename from fuzz/ref_corpus/signOperationalCertificate rename to fuzzing/corpus/signOperationalCertificate diff --git a/fuzz/ref_corpus/signTxOrdinaryMary0 b/fuzzing/corpus/signTxOrdinaryMary0 similarity index 100% rename from fuzz/ref_corpus/signTxOrdinaryMary0 rename to fuzzing/corpus/signTxOrdinaryMary0 diff --git a/fuzz/ref_corpus/signTxOrdinaryMary1 b/fuzzing/corpus/signTxOrdinaryMary1 similarity index 100% rename from fuzz/ref_corpus/signTxOrdinaryMary1 rename to fuzzing/corpus/signTxOrdinaryMary1 diff --git a/fuzz/ref_corpus/signTxOrdinaryMary2 b/fuzzing/corpus/signTxOrdinaryMary2 similarity index 100% rename from fuzz/ref_corpus/signTxOrdinaryMary2 rename to fuzzing/corpus/signTxOrdinaryMary2 diff --git a/fuzz/ref_corpus/signTxOrdinaryMary3 b/fuzzing/corpus/signTxOrdinaryMary3 similarity index 100% rename from fuzz/ref_corpus/signTxOrdinaryMary3 rename to fuzzing/corpus/signTxOrdinaryMary3 diff --git a/fuzz/ref_corpus/signTxOrdinaryMary4 b/fuzzing/corpus/signTxOrdinaryMary4 similarity index 100% rename from fuzz/ref_corpus/signTxOrdinaryMary4 rename to fuzzing/corpus/signTxOrdinaryMary4 diff --git a/fuzz/ref_corpus/signTxOrdinaryMary5 b/fuzzing/corpus/signTxOrdinaryMary5 similarity index 100% rename from fuzz/ref_corpus/signTxOrdinaryMary5 rename to fuzzing/corpus/signTxOrdinaryMary5 diff --git a/fuzz/ref_corpus/signTxOrdinaryMary6 b/fuzzing/corpus/signTxOrdinaryMary6 similarity index 100% rename from fuzz/ref_corpus/signTxOrdinaryMary6 rename to fuzzing/corpus/signTxOrdinaryMary6 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOperator0 b/fuzzing/corpus/signTxPoolRegistrationOKOperator0 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOperator0 rename to fuzzing/corpus/signTxPoolRegistrationOKOperator0 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOperator1 b/fuzzing/corpus/signTxPoolRegistrationOKOperator1 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOperator1 rename to fuzzing/corpus/signTxPoolRegistrationOKOperator1 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOperator2 b/fuzzing/corpus/signTxPoolRegistrationOKOperator2 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOperator2 rename to fuzzing/corpus/signTxPoolRegistrationOKOperator2 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOwner0 b/fuzzing/corpus/signTxPoolRegistrationOKOwner0 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOwner0 rename to fuzzing/corpus/signTxPoolRegistrationOKOwner0 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOwner1 b/fuzzing/corpus/signTxPoolRegistrationOKOwner1 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOwner1 rename to fuzzing/corpus/signTxPoolRegistrationOKOwner1 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOwner2 b/fuzzing/corpus/signTxPoolRegistrationOKOwner2 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOwner2 rename to fuzzing/corpus/signTxPoolRegistrationOKOwner2 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOwner3 b/fuzzing/corpus/signTxPoolRegistrationOKOwner3 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOwner3 rename to fuzzing/corpus/signTxPoolRegistrationOKOwner3 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOwner4 b/fuzzing/corpus/signTxPoolRegistrationOKOwner4 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOwner4 rename to fuzzing/corpus/signTxPoolRegistrationOKOwner4 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOwner5 b/fuzzing/corpus/signTxPoolRegistrationOKOwner5 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOwner5 rename to fuzzing/corpus/signTxPoolRegistrationOKOwner5 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOwner6 b/fuzzing/corpus/signTxPoolRegistrationOKOwner6 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOwner6 rename to fuzzing/corpus/signTxPoolRegistrationOKOwner6 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOwner7 b/fuzzing/corpus/signTxPoolRegistrationOKOwner7 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOwner7 rename to fuzzing/corpus/signTxPoolRegistrationOKOwner7 diff --git a/fuzz/ref_corpus/signTxPoolRegistrationOKOwner8 b/fuzzing/corpus/signTxPoolRegistrationOKOwner8 similarity index 100% rename from fuzz/ref_corpus/signTxPoolRegistrationOKOwner8 rename to fuzzing/corpus/signTxPoolRegistrationOKOwner8 diff --git a/fuzz/ref_corpus/signtx b/fuzzing/corpus/signtx similarity index 100% rename from fuzz/ref_corpus/signtx rename to fuzzing/corpus/signtx diff --git a/fuzzing/include/glyphs.h b/fuzzing/include/glyphs.h new file mode 100644 index 00000000..1e352b05 --- /dev/null +++ b/fuzzing/include/glyphs.h @@ -0,0 +1,12 @@ +#pragma once +#include +#include + +extern const bagl_icon_details_t C_icon_crossmark; +extern const bagl_icon_details_t C_icon_loader; +extern const bagl_icon_details_t C_icon_eye; +extern const bagl_icon_details_t C_icon_validate_14; +extern const bagl_icon_details_t C_icon_left; +extern const bagl_icon_details_t C_icon_right; +extern const bagl_icon_details_t C_icon_app; +extern const bagl_icon_details_t C_icon_dashboard_x; \ No newline at end of file diff --git a/fuzzing/include/harness.h b/fuzzing/include/harness.h new file mode 100644 index 00000000..e69de29b diff --git a/fuzzing/src/all_harness.c b/fuzzing/src/all_harness.c new file mode 100644 index 00000000..45f8753e --- /dev/null +++ b/fuzzing/src/all_harness.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include + +uint8_t G_io_apdu_buffer[IO_APDU_BUFFER_SIZE]; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + + UX_INIT(); + + uint8_t *input = NULL; + bool is_first = true; + + while (size > 5) { + io_state = IO_EXPECT_NONE; + uint8_t ins = data[0]; + uint8_t p1 = data[1]; + uint8_t p2 = data[2]; + uint8_t lc = data[3]; + + data += sizeof(uint8_t) * 4; + size -= sizeof(uint8_t) * 4; + + if (size < lc) { + return 0; + } + + uint8_t *input = malloc(lc); + if (input == NULL) { + return 0; + } + + memcpy(input, data, lc); + + data += lc; + size -= lc; + + handler_fn_t *handler = lookupHandler(ins); + + if (handler == NULL) { + free(input); + return 0; + } + BEGIN_TRY { + TRY { handler(p1, p2, input, lc, is_first); } + CATCH_ALL {} + FINALLY {} + } + END_TRY; + + is_first = false; + free(input); + } + return 0; +} \ No newline at end of file diff --git a/fuzzing/src/deriveAddress_harness.c b/fuzzing/src/deriveAddress_harness.c new file mode 100644 index 00000000..eece7ada --- /dev/null +++ b/fuzzing/src/deriveAddress_harness.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include +#include + +uint8_t G_io_apdu_buffer[IO_APDU_BUFFER_SIZE]; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + + UX_INIT(); + + uint8_t *input = NULL; + bool is_first = true; + + while (size > 5) { + io_state = IO_EXPECT_NONE; + uint8_t ins = data[0]; + uint8_t p1 = data[1]; + uint8_t p2 = data[2]; + uint8_t lc = data[3]; + + data += sizeof(uint8_t) * 4; + size -= sizeof(uint8_t) * 4; + + if (size < lc) { + return 0; + } + + uint8_t *input = malloc(lc); + if (input == NULL) { + return 0; + } + + memcpy(input, data, lc); + + data += lc; + size -= lc; + + BEGIN_TRY { + TRY { deriveAddress_handleAPDU(p1, p2, input, lc, is_first); } + CATCH_ALL {} + FINALLY {} + } + END_TRY; + + is_first = false; + free(input); + } + return 0; +} \ No newline at end of file diff --git a/fuzzing/src/deriveNativeScriptHash_harness.c b/fuzzing/src/deriveNativeScriptHash_harness.c new file mode 100644 index 00000000..5bc34bde --- /dev/null +++ b/fuzzing/src/deriveNativeScriptHash_harness.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include + +uint8_t G_io_apdu_buffer[IO_APDU_BUFFER_SIZE]; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + + UX_INIT(); + + uint8_t *input = NULL; + bool is_first = true; + + while (size > 5) { + io_state = IO_EXPECT_NONE; + uint8_t ins = data[0]; + uint8_t p1 = data[1]; + uint8_t p2 = data[2]; + uint8_t lc = data[3]; + + data += sizeof(uint8_t) * 4; + size -= sizeof(uint8_t) * 4; + + if (size < lc) { + return 0; + } + + uint8_t *input = malloc(lc); + if (input == NULL) { + return 0; + } + + memcpy(input, data, lc); + + data += lc; + size -= lc; + + BEGIN_TRY { + TRY { deriveNativeScriptHash_handleAPDU(p1, p2, input, lc, is_first); } + CATCH_ALL {} + FINALLY {} + } + END_TRY; + + is_first = false; + free(input); + } + return 0; +} \ No newline at end of file diff --git a/fuzzing/src/getPublicKeys_harness.c b/fuzzing/src/getPublicKeys_harness.c new file mode 100644 index 00000000..204ca81a --- /dev/null +++ b/fuzzing/src/getPublicKeys_harness.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include + +uint8_t G_io_apdu_buffer[IO_APDU_BUFFER_SIZE]; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + + UX_INIT(); + + uint8_t *input = NULL; + bool is_first = true; + + while (size > 5) { + io_state = IO_EXPECT_NONE; + uint8_t ins = data[0]; + uint8_t p1 = data[1]; + uint8_t p2 = data[2]; + uint8_t lc = data[3]; + + data += sizeof(uint8_t) * 4; + size -= sizeof(uint8_t) * 4; + + if (size < lc) { + return 0; + } + + uint8_t *input = malloc(lc); + if (input == NULL) { + return 0; + } + + memcpy(input, data, lc); + + data += lc; + size -= lc; + + BEGIN_TRY { + TRY { getPublicKeys_handleAPDU(p1, p2, input, lc, is_first); } + CATCH_ALL {} + FINALLY {} + } + END_TRY; + + is_first = false; + free(input); + } + return 0; +} \ No newline at end of file diff --git a/fuzzing/src/glyphs.c b/fuzzing/src/glyphs.c new file mode 100644 index 00000000..9d726638 --- /dev/null +++ b/fuzzing/src/glyphs.c @@ -0,0 +1,12 @@ +#include +#include + +const bagl_icon_details_t C_icon_crossmark = {0}; +const bagl_icon_details_t C_icon_loader = {0}; +const bagl_icon_details_t C_icon_eye = {0}; +const bagl_icon_details_t C_icon_validate_14 = {0}; +const bagl_icon_details_t C_icon_left = {0}; +const bagl_icon_details_t C_icon_right = {0}; +const bagl_icon_details_t C_icon_app = {0}; +const bagl_icon_details_t C_icon_dashboard_x = {0}; + diff --git a/fuzzing/src/os_mocks.c b/fuzzing/src/os_mocks.c new file mode 100644 index 00000000..611244a5 --- /dev/null +++ b/fuzzing/src/os_mocks.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include +#include +#include +#include + +void nvm_write(void *dst_adr, void *src_adr, unsigned int src_len) { + memcpy(dst_adr, src_adr, src_len); +} + +unsigned int os_serial(unsigned char *serial, unsigned int maxlength) { + memset(serial, 'A', maxlength); + return maxlength; +} + +void __attribute__((noreturn)) os_sched_exit(bolos_task_status_t exit_code) { + exit(exit_code); +} + +void os_longjmp(unsigned int exception) { + longjmp(try_context_get()->jmp_buf, exception); +} + +try_context_t *current_context = NULL; +try_context_t *try_context_get(void) { return current_context; } + +try_context_t *try_context_set(try_context_t *ctx) { + try_context_t *previous_ctx = current_context; + current_context = ctx; + return previous_ctx; +} + +void *pic(void *linked_addr) { return linked_addr; } +// void ui_idle(){}; +void halt() { + for (;;) + ; +}; +unsigned short io_exchange(unsigned char chan, unsigned short tx_len) { + return 0; +}; +unsigned short io_seph_recv(unsigned char *buffer, unsigned short maxlength, + unsigned int flags) { + return 0; +}; +cx_err_t cx_blake2b_init_no_throw(cx_blake2b_t *hash, size_t size) { + return CX_OK; +}; +cx_err_t cx_hash_no_throw(cx_hash_t *hash, uint32_t mode, const uint8_t *in, + size_t len, uint8_t *out, size_t out_len) { + return CX_OK; +}; +size_t cx_hash_get_size(const cx_hash_t *ctx) { return 32; }; +void io_seph_send(const unsigned char *buffer, unsigned short length){}; +cx_err_t cx_sha3_init_no_throw(cx_sha3_t *hash, size_t size) { return CX_OK; }; +unsigned int io_seph_is_status_sent(void) { return 0; }; +bolos_bool_t os_perso_isonboarded(void) { return (bolos_bool_t)BOLOS_UX_OK; }; +void io_seproxyhal_display_default(const bagl_element_t *bagl) { + if (bagl->text) { + printf("[-] %s\n", bagl->text); + } +} +void io_seproxyhal_init_ux(void){}; +bolos_task_status_t os_sched_last_status(unsigned int task_idx) { return 1; }; +bolos_bool_t os_global_pin_is_validated(void) { + return (bolos_bool_t)BOLOS_UX_OK; +} + +cx_err_t cx_eddsa_get_public_key_no_throw(const cx_ecfp_private_key_t *pv_key, + cx_md_t hashID, + cx_ecfp_public_key_t *pu_key, + uint8_t *a, size_t a_len, uint8_t *h, + size_t h_len) { + pu_key->W_len = 65; + memset(pu_key, 'A', pu_key->W_len); + return CX_OK; +} + +cx_err_t cx_eddsa_sign_no_throw(const cx_ecfp_private_key_t *pvkey, + cx_md_t hashID, const uint8_t *hash, + size_t hash_len, uint8_t *sig, size_t sig_len) { + return CX_OK; +} + +cx_err_t cx_ecdomain_parameters_length(cx_curve_t cv, size_t *length) { + // cardano uses CX_CURVE_Ed25519 + if (cv == CX_CURVE_Ed25519) { + *length = 32; + return CX_OK; + } + + exit(1); + return CX_INVALID_PARAMETER; +} + +void os_perso_derive_node_with_seed_key( + unsigned int mode, cx_curve_t curve, const unsigned int *path, + unsigned int pathLength, unsigned char *privateKey, unsigned char *chain, + unsigned char *seed_key, unsigned int seed_key_length) {} \ No newline at end of file diff --git a/fuzzing/src/signCVote_harness.c b/fuzzing/src/signCVote_harness.c new file mode 100644 index 00000000..e3119912 --- /dev/null +++ b/fuzzing/src/signCVote_harness.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include + +uint8_t G_io_apdu_buffer[IO_APDU_BUFFER_SIZE]; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + + UX_INIT(); + + uint8_t *input = NULL; + bool is_first = true; + + while (size > 5) { + io_state = IO_EXPECT_NONE; + uint8_t ins = data[0]; + uint8_t p1 = data[1]; + uint8_t p2 = data[2]; + uint8_t lc = data[3]; + + data += sizeof(uint8_t) * 4; + size -= sizeof(uint8_t) * 4; + + if (size < lc) { + return 0; + } + + uint8_t *input = malloc(lc); + if (input == NULL) { + return 0; + } + + memcpy(input, data, lc); + + data += lc; + size -= lc; + + BEGIN_TRY { + TRY { signCVote_handleAPDU(p1, p2, input, lc, is_first); } + CATCH_ALL {} + FINALLY {} + } + END_TRY; + + is_first = false; + free(input); + } + return 0; +} \ No newline at end of file diff --git a/fuzzing/src/signOpCert_harness.c b/fuzzing/src/signOpCert_harness.c new file mode 100644 index 00000000..eb89f8f0 --- /dev/null +++ b/fuzzing/src/signOpCert_harness.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include + +uint8_t G_io_apdu_buffer[IO_APDU_BUFFER_SIZE]; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + + UX_INIT(); + + uint8_t *input = NULL; + bool is_first = true; + + while (size > 5) { + io_state = IO_EXPECT_NONE; + uint8_t ins = data[0]; + uint8_t p1 = data[1]; + uint8_t p2 = data[2]; + uint8_t lc = data[3]; + + data += sizeof(uint8_t) * 4; + size -= sizeof(uint8_t) * 4; + + if (size < lc) { + return 0; + } + + uint8_t *input = malloc(lc); + if (input == NULL) { + return 0; + } + + memcpy(input, data, lc); + + data += lc; + size -= lc; + + BEGIN_TRY { + TRY { signOpCert_handleAPDU(p1, p2, input, lc, is_first); } + CATCH_ALL {} + FINALLY {} + } + END_TRY; + + is_first = false; + free(input); + } + return 0; +} \ No newline at end of file diff --git a/fuzzing/src/signTx_harness.c b/fuzzing/src/signTx_harness.c new file mode 100644 index 00000000..48a4c624 --- /dev/null +++ b/fuzzing/src/signTx_harness.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include + +uint8_t G_io_apdu_buffer[IO_APDU_BUFFER_SIZE]; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + + UX_INIT(); + + uint8_t *input = NULL; + bool is_first = true; + + while (size > 5) { + io_state = IO_EXPECT_NONE; + uint8_t ins = data[0]; + uint8_t p1 = data[1]; + uint8_t p2 = data[2]; + uint8_t lc = data[3]; + + data += sizeof(uint8_t) * 4; + size -= sizeof(uint8_t) * 4; + + if (size < lc) { + return 0; + } + + uint8_t *input = malloc(lc); + if (input == NULL) { + return 0; + } + + memcpy(input, data, lc); + + data += lc; + size -= lc; + + BEGIN_TRY { + TRY { signTx_handleAPDU(p1, p2, input, lc, is_first); } + CATCH_ALL {} + FINALLY {} + } + END_TRY; + + is_first = false; + free(input); + } + return 0; +} \ No newline at end of file diff --git a/src/bip44.c b/src/bip44.c index 9f6b62a9..883a98e9 100644 --- a/src/bip44.c +++ b/src/bip44.c @@ -4,9 +4,9 @@ #include "hash.h" #include "keyDerivation.h" -static const uint32_t CARDANO_CHAIN_EXTERNAL = 0; -static const uint32_t CARDANO_CHAIN_INTERNAL = 1; -static const uint32_t CARDANO_CHAIN_STAKING_KEY = 2; +#define CARDANO_CHAIN_EXTERNAL 0 +#define CARDANO_CHAIN_INTERNAL 1 +#define CARDANO_CHAIN_STAKING_KEY 2 static const uint32_t MAX_REASONABLE_ACCOUNT = 100; static const uint32_t MAX_REASONABLE_ADDRESS = 1000000; diff --git a/src/uiHelpers.h b/src/uiHelpers.h index b7627844..bc6c8eb9 100644 --- a/src/uiHelpers.h +++ b/src/uiHelpers.h @@ -42,7 +42,7 @@ extern bolos_ux_params_t G_ux_params; #define UI_STEP(NEXT_STEP) \ *__ui_step_ptr = NEXT_STEP; \ } \ - __attribute__((fallthrough)); + __attribute__((fallthrough)); \ case NEXT_STEP: { #else #define UI_STEP(NEXT_STEP) \ diff --git a/src/uiScreens_bagl.c b/src/uiScreens_bagl.c index 0c2791a7..1e158a0c 100644 --- a/src/uiScreens_bagl.c +++ b/src/uiScreens_bagl.c @@ -768,7 +768,9 @@ void ui_displayPoolRelayScreen( char firstLine[20] = {0}; explicit_bzero(firstLine, SIZEOF(firstLine)); { + #ifndef FUZZING STATIC_ASSERT(sizeof(relayIndex + 1) <= sizeof(unsigned), "oversized type for %u"); + #endif STATIC_ASSERT(!IS_SIGNED(relayIndex + 1), "signed type for %u"); // indexed from 0 as discussed with IOHK on Slack snprintf(firstLine, SIZEOF(firstLine), "Relay #%u", relayIndex); diff --git a/src/utils.h b/src/utils.h index a8be7df5..7d54ec09 100644 --- a/src/utils.h +++ b/src/utils.h @@ -17,6 +17,7 @@ #define ARRAY_LEN(arr) \ (sizeof(arr) / sizeof((arr)[0]) + ARRAY_NOT_A_PTR(arr)) +#ifndef FUZZING // Does not compile if x *might* be a pointer of some kind // Might produce false positives on small structs... // Note: ARRAY_NOT_A_PTR does not compile if arg is a struct so this is a workaround @@ -27,6 +28,9 @@ #define SIZEOF(var) \ (sizeof(var) + SIZEOF_NOT_A_PTR(var)) +#else +#define SIZEOF(var) sizeof(var) +#endif #define ASSERT_TYPE(expr, expected_type) \ STATIC_ASSERT( \ From df2ffa426b8d2e0149f18ad8cdfd0d2c533d562a Mon Sep 17 00:00:00 2001 From: Jorge Martins Date: Fri, 13 Oct 2023 17:00:07 +0200 Subject: [PATCH 097/105] delete unused harness.h --- fuzzing/include/harness.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 fuzzing/include/harness.h diff --git a/fuzzing/include/harness.h b/fuzzing/include/harness.h deleted file mode 100644 index e69de29b..00000000 From 37963c9b18eddf4f8d8f65626bbf14a3d4836017 Mon Sep 17 00:00:00 2001 From: Jorge Martins Date: Fri, 13 Oct 2023 17:11:44 +0200 Subject: [PATCH 098/105] remove verbose while building fuzzers --- .clusterfuzzlite/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.clusterfuzzlite/build.sh b/.clusterfuzzlite/build.sh index 6bf7a52e..6fc23299 100644 --- a/.clusterfuzzlite/build.sh +++ b/.clusterfuzzlite/build.sh @@ -4,6 +4,6 @@ pushd fuzzing cmake -DBOLOS_SDK=../BOLOS_SDK -Bbuild -H. -make -C build VERBOSE=1 +make -C build mv build/*_harness $OUT popd \ No newline at end of file From cd2145bea415d18f139fff3d666ad627622d9960 Mon Sep 17 00:00:00 2001 From: Jorge Martins Date: Mon, 23 Oct 2023 14:03:17 +0200 Subject: [PATCH 099/105] build cardano library once, fix fuzzing false positive --- fuzzing/CMakeLists.txt | 3 ++- src/keyDerivation.c | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt index cbc810f7..fe7e9fe6 100644 --- a/fuzzing/CMakeLists.txt +++ b/fuzzing/CMakeLists.txt @@ -152,6 +152,7 @@ set(SOURCE ) +add_library(cardano ${SOURCE}) set(harnesses all_harness @@ -166,6 +167,6 @@ set(harnesses foreach(harness IN LISTS harnesses) add_executable(${harness} ./src/${harness}.c - ${SOURCE} ) + target_link_libraries(${harness} PUBLIC cardano) endforeach() \ No newline at end of file diff --git a/src/keyDerivation.c b/src/keyDerivation.c index 6e820042..5f733f71 100644 --- a/src/keyDerivation.c +++ b/src/keyDerivation.c @@ -49,7 +49,6 @@ void deriveExtendedPublicKey( // if the path is invalid, it's a bug in previous validation ASSERT(policyForDerivePrivateKey(pathSpec) != POLICY_DENY); - #ifndef FUZZING { cx_err_t error = crypto_get_pubkey(pathSpec->path, pathSpec->length, @@ -60,7 +59,6 @@ void deriveExtendedPublicKey( ASSERT(false); } } - #endif extractRawPublicKey(rawPubkey, out->pubKey, SIZEOF(out->pubKey)); From ce737a2a670678d529b2508f7197f409a7f5f9fd Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 25 Oct 2023 10:38:05 +0200 Subject: [PATCH 100/105] Bump Version to 6.1.2 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 186947d2..5e18b380 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ APPNAME = "Cardano ADA" APPVERSION_M = 6 APPVERSION_N = 1 -APPVERSION_P = 1 +APPVERSION_P = 2 APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" ifeq ($(BOLOS_SDK),) From a720f0a7f4a4e05efeae6349ff85780ae4ce7c89 Mon Sep 17 00:00:00 2001 From: Sarah Gliner <105934250+sgliner-ledger@users.noreply.github.com> Date: Wed, 29 Nov 2023 11:45:56 +0100 Subject: [PATCH 101/105] [auto]: add PR template --- .github/PULL_REQUEST_TEMPLATE.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..98b720fe --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,8 @@ +# Checklist + +- [ ] App update process has been followed +- [ ] Target branch is `develop` +- [ ] Application version has been bumped + + From 973b5959ed083abf027b3d41052981f462ff39ba Mon Sep 17 00:00:00 2001 From: Xavier Chapron Date: Thu, 30 Nov 2023 11:10:34 +0100 Subject: [PATCH 102/105] Makefile: Set APP_LOAD_PARAMS before including Makefile.rules This will become necessary once https://github.com/LedgerHQ/ledger-secure-sdk/pull/472 is merged and cherry-picked. --- Makefile | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 5e18b380..5d453aa0 100644 --- a/Makefile +++ b/Makefile @@ -153,12 +153,6 @@ all: default # Build # ############## -# import generic rules from the sdk -include $(BOLOS_SDK)/Makefile.rules - -#add dependency on custom makefile filename -dep/%.d: %.c Makefile - listvariants: @echo VARIANTS COIN cardano_ada @@ -203,3 +197,6 @@ format: size: all $(GCCPATH)arm-none-eabi-size --format=gnu bin/app.elf + +# import generic rules from the sdk +include $(BOLOS_SDK)/Makefile.rules From dd0dc573f4a786b9610716fb7148d97ac5a751db Mon Sep 17 00:00:00 2001 From: Xavier Chapron Date: Thu, 30 Nov 2023 16:23:00 +0100 Subject: [PATCH 103/105] Fix build warning by dropping unused stuff --- Makefile | 2 -- src/io.c | 1 - src/main.c | 6 ------ 3 files changed, 9 deletions(-) diff --git a/Makefile b/Makefile index 5d453aa0..c03f1fee 100644 --- a/Makefile +++ b/Makefile @@ -63,8 +63,6 @@ DEFINES += HAVE_SPRINTF HAVE_SNPRINTF_FORMAT_U DEFINES += APPVERSION=\"$(APPVERSION)\" DEFINES += MAJOR_VERSION=$(APPVERSION_M) MINOR_VERSION=$(APPVERSION_N) PATCH_VERSION=$(APPVERSION_P) -DEFINES += UNUSED\(x\)=\(void\)x - ## USB HID? DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=4 IO_HID_EP_LENGTH=64 HAVE_USB_APDU diff --git a/src/io.c b/src/io.c index 5f243e46..a85bfc50 100644 --- a/src/io.c +++ b/src/io.c @@ -181,7 +181,6 @@ unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) return 0; } -STATIC_ASSERT(CX_APILEVEL >= 9, "bad api level"); static const unsigned PIN_VERIFIED = BOLOS_UX_OK; // Seems to work for api 9/10 bool device_is_unlocked() diff --git a/src/main.c b/src/main.c index 03e9a451..560e21cb 100644 --- a/src/main.c +++ b/src/main.c @@ -39,12 +39,6 @@ #include "uiScreens_nbgl.h" #endif -// The whole app is designed for a specific api level. -// In case there is an api change, first *verify* changes -// (especially potential security implications) before bumping -// the API level! -STATIC_ASSERT(CX_APILEVEL >= 9, "bad api level"); - static const int INS_NONE = -1; static const uint8_t CLA = 0xD7; From 0deb1660d75aa77ca2b437e302554745f68b4826 Mon Sep 17 00:00:00 2001 From: Sarah Gliner <105934250+sgliner-ledger@users.noreply.github.com> Date: Tue, 27 Feb 2024 17:25:02 +0100 Subject: [PATCH 104/105] [auto] Update screenshot --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 98b720fe..f2fb620f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,5 +4,5 @@ - [ ] Target branch is `develop` - [ ] Application version has been bumped - From 7534d00c2ddd6605831bc04807fc5102f3a0c938 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 13 Mar 2024 14:19:02 +0100 Subject: [PATCH 105/105] [auto] Add manifest --- ledger_app.toml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 ledger_app.toml diff --git a/ledger_app.toml b/ledger_app.toml new file mode 100644 index 00000000..acd4ba11 --- /dev/null +++ b/ledger_app.toml @@ -0,0 +1,4 @@ +[app] +build_directory = "./" +sdk = "C" +devices = ["nanos", "nanox", "nanos+", "stax"]