diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 68f2c168b..5d3bb29d4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -343,6 +343,91 @@ jobs: bin/*.elf retention-days: 90 + build-arm-firmware-btc-only: + needs: [check-submodules, secret-scan] + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Init submodules + run: | + git submodule update --init deps/crypto/trezor-firmware + git submodule update --init deps/device-protocol + git submodule update --init --recursive deps/python-keepkey + git submodule update --init deps/googletest + git submodule update --init deps/qrenc/QR-Code-generator + git submodule update --init deps/sca-hardening/SecAESSTM32 + + - name: Cache base image + id: cache-base + uses: actions/cache@v4 + with: + path: /tmp/base-image.tar + key: base-image-${{ env.BASE_IMAGE }} + + - name: Pull and cache base image + if: steps.cache-base.outputs.cache-hit != 'true' + run: | + docker pull ${{ env.BASE_IMAGE }} + docker save ${{ env.BASE_IMAGE }} -o /tmp/base-image.tar + + - name: Load base image from cache + if: steps.cache-base.outputs.cache-hit == 'true' + run: docker load -i /tmp/base-image.tar + + - name: Extract firmware version + id: version + run: | + FW_VERSION=$(sed -n '/^project/,/)/p' CMakeLists.txt | grep -oP '\d+\.\d+\.\d+') + GIT_SHORT=$(git rev-parse --short HEAD) + echo "fw_version=${FW_VERSION}" >> "$GITHUB_OUTPUT" + echo "git_short=${GIT_SHORT}" >> "$GITHUB_OUTPUT" + echo "Firmware version: ${FW_VERSION} (${GIT_SHORT}) [BTC-only]" + + - name: Cross-compile BTC-only firmware for ARM + run: | + docker run --rm \ + -v ${{ github.workspace }}:/root/keepkey-firmware:z \ + ${{ env.BASE_IMAGE }} /bin/sh -c "\ + mkdir /root/build && cd /root/build && \ + cmake -C /root/keepkey-firmware/cmake/caches/device.cmake /root/keepkey-firmware \ + -DCOIN_SUPPORT=BTC \ + -DVARIANTS=NoObsoleteVariants \ + -DCMAKE_BUILD_TYPE=MinSizeRel \ + -DCMAKE_COLOR_MAKEFILE=ON && \ + make && \ + mkdir -p /root/keepkey-firmware/bin-btc && \ + cp bin/*.bin /root/keepkey-firmware/bin-btc/ && \ + cp bin/*.elf /root/keepkey-firmware/bin-btc/ && \ + chmod -R a+rw /root/keepkey-firmware/bin-btc" + + - name: Rename firmware artifacts + run: | + cd bin-btc + for f in *.bin; do + [ -f "$f" ] || continue + mv "$f" "firmware.keepkey.btc-only.v${{ steps.version.outputs.fw_version }}-${{ steps.version.outputs.git_short }}-${f}" + done + for f in *.elf; do + [ -f "$f" ] || continue + mv "$f" "firmware.keepkey.btc-only.v${{ steps.version.outputs.fw_version }}-${{ steps.version.outputs.git_short }}-${f}" + done + ls -lh + echo "::notice::BTC-only firmware v${{ steps.version.outputs.fw_version }} built successfully" + + - name: Upload BTC-only firmware artifacts + uses: actions/upload-artifact@v4 + with: + name: firmware-btc-only-v${{ steps.version.outputs.fw_version }}-${{ steps.version.outputs.git_short }} + path: | + bin-btc/*.bin + bin-btc/*.elf + retention-days: 90 + # ═══════════════════════════════════════════════════════════ # STAGE 3: TEST — run only after builds succeed # ═══════════════════════════════════════════════════════════ @@ -435,7 +520,7 @@ jobs: # ═══════════════════════════════════════════════════════════ publish-emulator: - needs: [unit-tests, python-integration-tests, build-arm-firmware] + needs: [unit-tests, python-integration-tests, build-arm-firmware, build-arm-firmware-btc-only] if: >- github.event_name == 'workflow_dispatch' && github.event.inputs.publish_emulator == 'true' diff --git a/include/keepkey/firmware/coins.def b/include/keepkey/firmware/coins.def index 7b1fd3c11..3d7a3a972 100644 --- a/include/keepkey/firmware/coins.def +++ b/include/keepkey/firmware/coins.def @@ -6,7 +6,6 @@ X(true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 19 X(true, "BitcoinCash", true, "BCH", true, 0, true, 500000, true, 5, true, "Bitcoin Signed Message:\n", true, 0x80000091, true, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, true, true, SECP256K1_STRING, true, "bitcoincash", false, "", false, false, false, 0, false, 0, false, "", true, false ) X(true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, true, "Namecoin Signed Message:\n", true, 0x80000007, false, 0, true, 8, false, NO_CONTRACT, true, 27108450, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "", true, false ) X(true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 50, true, "Litecoin Signed Message:\n", true, 0x80000002, false, 0, true, 8, false, NO_CONTRACT, true, 27108450, true, true, true, false, true, SECP256K1_STRING, false, "", true, "ltc", false, false, true, 28471030, true, 78792518, false, "", true, false ) -X(true, "Lynx", true, "LYNX", true, 45, true, 1000000, true, 22, true, "Bitcoin Signed Message:\n", true, 0x800000bf, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "lynx", false, false, true, 77429938, true, 78792518, false, "", true, true ) X(true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22, true, "Dogecoin Signed Message:\n", true, 0x80000003, false, 0, true, 8, false, NO_CONTRACT, true, 49990397, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "", true, false ) X(true, "Dash", true, "DASH", true, 76, true, 100000, true, 16, true, "DarkCoin Signed Message:\n", true, 0x80000005, false, 0, true, 8, false, NO_CONTRACT, true, 50221772, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "", true, false ) X(true, ETHEREUM, true, "ETH", true, NA, true, 100000, true, NA, true, "Ethereum Signed Message:\n", true, 0x8000003c, true, 1, true, 18, false, NO_CONTRACT, false, 0, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "", true, false ) diff --git a/include/keepkey/firmware/fsm.h b/include/keepkey/firmware/fsm.h index 515b23277..e5f3e8f0b 100644 --- a/include/keepkey/firmware/fsm.h +++ b/include/keepkey/firmware/fsm.h @@ -77,6 +77,9 @@ void fsm_msgWordAck(WordAck *msg); void fsm_msgCharacterAck(CharacterAck *msg); void fsm_msgApplyPolicies(ApplyPolicies *msg); +// BIP-85 (chain-agnostic, available in all builds) +void fsm_msgGetBip85Mnemonic(const GetBip85Mnemonic *msg); + #ifndef BITCOIN_ONLY // ethereum void fsm_msgEthereumGetAddress(EthereumGetAddress *msg); @@ -119,7 +122,6 @@ void fsm_msgMayachainGetAddress(const MayachainGetAddress *msg); void fsm_msgMayachainSignTx(const MayachainSignTx *msg); void fsm_msgMayachainMsgAck(const MayachainMsgAck *msg); -void fsm_msgGetBip85Mnemonic(const GetBip85Mnemonic *msg); void fsm_msgSolanaGetAddress(const SolanaGetAddress *msg); void fsm_msgSolanaSignTx(const SolanaSignTx *msg); void fsm_msgSolanaSignMessage(const SolanaSignMessage *msg); diff --git a/include/keepkey/transport/messages-ton.options b/include/keepkey/transport/messages-ton.options index bec6d9857..18c064289 100644 --- a/include/keepkey/transport/messages-ton.options +++ b/include/keepkey/transport/messages-ton.options @@ -9,6 +9,4 @@ TonSignTx.coin_name max_size:21 TonSignTx.raw_tx max_size:1024 TonSignTx.to_address max_size:50 -TonAddress.address max_size:50 -TonAddress.raw_address max_size:70 TonSignedTx.signature max_size:64 diff --git a/include/keepkey/transport/messages-tron.options b/include/keepkey/transport/messages-tron.options index 05aef1433..fae7bfadf 100644 --- a/include/keepkey/transport/messages-tron.options +++ b/include/keepkey/transport/messages-tron.options @@ -17,13 +17,5 @@ TronSignTx.contract_type max_size:64 TronSignTx.to_address max_size:35 TronSignTx.data max_size:256 -TronSignTx.address_n max_count:8 -TronSignTx.coin_name max_size:21 -TronSignTx.raw_data max_size:1024 -TronSignTx.ref_block_bytes max_size:2 -TronSignTx.ref_block_hash max_size:8 -TronSignTx.contract_type max_size:50 -TronSignTx.to_address max_size:35 -TronAddress.address max_size:35 TronSignedTx.signature max_size:65 TronSignedTx.serialized_tx max_size:1024 diff --git a/lib/firmware/CMakeLists.txt b/lib/firmware/CMakeLists.txt index b5433849d..7a49a60e6 100644 --- a/lib/firmware/CMakeLists.txt +++ b/lib/firmware/CMakeLists.txt @@ -14,11 +14,10 @@ set(sources signing.c storage.c tiny-json.c - tron.c - ton.c transaction.c txin_check.c - u2f.c) + u2f.c + bip85.c) if(NOT "${COIN_SUPPORT}" STREQUAL "BTC") list(APPEND sources @@ -46,7 +45,6 @@ if(NOT "${COIN_SUPPORT}" STREQUAL "BTC") signtx_tendermint.c tendermint.c thorchain.c - bip85.c solana.c tron.c ton.c diff --git a/lib/firmware/fsm.c b/lib/firmware/fsm.c index 840d63ed6..66b163ff9 100644 --- a/lib/firmware/fsm.c +++ b/lib/firmware/fsm.c @@ -67,6 +67,8 @@ #include +#include "keepkey/firmware/bip85.h" + #ifndef BITCOIN_ONLY #include "keepkey/firmware/cosmos.h" #include "keepkey/firmware/binance.h" @@ -80,7 +82,6 @@ #include "keepkey/firmware/signtx_tendermint.h" #include "keepkey/firmware/tendermint.h" #include "keepkey/firmware/thorchain.h" -#include "keepkey/firmware/bip85.h" #include "keepkey/firmware/solana.h" #include "keepkey/firmware/tron.h" #include "keepkey/firmware/ton.h" @@ -292,6 +293,7 @@ void fsm_msgClearSession(ClearSession *msg) { #include "fsm_msg_coin.h" #include "fsm_msg_debug.h" #include "fsm_msg_crypto.h" +#include "fsm_msg_bip85.h" #ifndef BITCOIN_ONLY #include "fsm_msg_ethereum.h" #include "fsm_msg_nano.h" @@ -303,7 +305,6 @@ void fsm_msgClearSession(ClearSession *msg) { #include "fsm_msg_tendermint.h" #include "fsm_msg_thorchain.h" #include "fsm_msg_mayachain.h" -#include "fsm_msg_bip85.h" #include "fsm_msg_solana.h" #include "fsm_msg_tron.h" #include "fsm_msg_ton.h" diff --git a/lib/firmware/messagemap.def b/lib/firmware/messagemap.def index 88778736d..969af3b0d 100644 --- a/lib/firmware/messagemap.def +++ b/lib/firmware/messagemap.def @@ -33,6 +33,9 @@ MSG_IN(MessageType_MessageType_RecoveryDevice, RecoveryDevice, fsm_msgRecoveryDevice) MSG_IN(MessageType_MessageType_CharacterAck, CharacterAck, fsm_msgCharacterAck) MSG_IN(MessageType_MessageType_ApplyPolicies, ApplyPolicies, fsm_msgApplyPolicies) + + MSG_IN(MessageType_MessageType_GetBip85Mnemonic, GetBip85Mnemonic, fsm_msgGetBip85Mnemonic) + #ifndef BITCOIN_ONLY MSG_IN(MessageType_MessageType_EthereumGetAddress, EthereumGetAddress, fsm_msgEthereumGetAddress) MSG_IN(MessageType_MessageType_EthereumSignTx, EthereumSignTx, fsm_msgEthereumSignTx) @@ -75,8 +78,6 @@ MSG_IN(MessageType_MessageType_MayachainSignTx, MayachainSignTx, fsm_msgMayachainSignTx) MSG_IN(MessageType_MessageType_MayachainMsgAck, MayachainMsgAck, fsm_msgMayachainMsgAck) - MSG_IN(MessageType_MessageType_GetBip85Mnemonic, GetBip85Mnemonic, fsm_msgGetBip85Mnemonic) - MSG_IN(MessageType_MessageType_SolanaGetAddress, SolanaGetAddress, fsm_msgSolanaGetAddress) MSG_IN(MessageType_MessageType_SolanaSignTx, SolanaSignTx, fsm_msgSolanaSignTx) MSG_IN(MessageType_MessageType_SolanaSignMessage, SolanaSignMessage, fsm_msgSolanaSignMessage) @@ -113,6 +114,9 @@ MSG_OUT(MessageType_MessageType_PassphraseRequest, PassphraseRequest, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_WordRequest, WordRequest, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_CharacterRequest, CharacterRequest, NO_PROCESS_FUNC) + + MSG_OUT(MessageType_MessageType_Bip85Mnemonic, Bip85Mnemonic, NO_PROCESS_FUNC) + #ifndef BITCOIN_ONLY MSG_OUT(MessageType_MessageType_EthereumAddress, EthereumAddress, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_EthereumTxRequest, EthereumTxRequest, NO_PROCESS_FUNC) @@ -152,8 +156,6 @@ MSG_OUT(MessageType_MessageType_MayachainMsgRequest, MayachainMsgRequest, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_MayachainSignedTx, MayachainSignedTx, NO_PROCESS_FUNC) - MSG_OUT(MessageType_MessageType_Bip85Mnemonic, Bip85Mnemonic, NO_PROCESS_FUNC) - MSG_OUT(MessageType_MessageType_SolanaAddress, SolanaAddress, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_SolanaSignedTx, SolanaSignedTx, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_SolanaMessageSignature, SolanaMessageSignature, NO_PROCESS_FUNC)