diff --git a/app/bitcoin/bitcoin.h b/app/bitcoin/bitcoin.h new file mode 100644 index 0000000..059f226 --- /dev/null +++ b/app/bitcoin/bitcoin.h @@ -0,0 +1,62 @@ +#ifndef __BITCOIN__ +#define __BITCOIN__ + +#include +#include +#include "bitcoin/psbt.h" + +#define BTC_MAX_INPUTS 20 +#define BTC_MAX_OUTPUTS 20 + +typedef enum { + BTC_INPUT_TYPE_LEGACY, + BTC_INPUT_TYPE_LEGACY_WITH_REDEEM, + BTC_INPUT_TYPE_P2WPKH, + BTC_INPUT_TYPE_P2WSH, +} btc_input_type_t; + +typedef enum { + SIGHASH_DEFAULT = 0x00, + SIGHASH_ALL = 0x01, + SIGHASH_NONE = 0x02, + SIGHASH_SINGLE = 0x03, +} btc_sighash_flag_t; + +typedef struct { + uint8_t* script_pubkey; + size_t script_pubkey_len; + uint8_t* redeem_script; + size_t redeem_script_len; + uint8_t* witness_script; + size_t witness_script_len; + uint8_t* nonwitness_utxo; + size_t nonwitness_utxo_len; + uint8_t* amount; + uint8_t* bip32_path; + uint32_t bip32_path_len; + uint32_t master_fingerprint; + uint32_t sighash_flag; + btc_input_type_t input_type; + bool witness; + bool can_sign; +} psbt_input_data_t; + +typedef struct { + psbt_tx_t tx; + psbt_txin_t inputs[BTC_MAX_INPUTS]; + psbt_txout_t outputs[BTC_MAX_OUTPUTS]; + psbt_input_data_t input_data[BTC_MAX_INPUTS]; + size_t input_count; + size_t output_count; + + psbt_t psbt_out; + size_t index_in; + size_t index_out; + uint8_t hash_prevouts[SHA256_DIGEST_LENGTH]; + uint8_t hash_sequence[SHA256_DIGEST_LENGTH]; + uint8_t hash_outputs[SHA256_DIGEST_LENGTH]; + + app_err_t error; +} btc_tx_ctx_t; + +#endif diff --git a/app/core/core_btc.c b/app/core/core_btc.c index 1ef8d9f..c4911c9 100644 --- a/app/core/core_btc.c +++ b/app/core/core_btc.c @@ -1,5 +1,6 @@ #include "core.h" #include "mem.h" +#include "bitcoin/bitcoin.h" #include "bitcoin/psbt.h" #include "bitcoin/compactsize.h" #include "crypto/script.h" @@ -9,9 +10,6 @@ #include "ur/ur_encode.h" #include "util/tlv.h" -#define BTC_MAX_INPUTS 20 -#define BTC_MAX_OUTPUTS 20 - #define BTC_TXID_LEN 32 #define BTC_MSG_MAGIC_LEN 25 #define BTC_MSG_SIG_LEN 65 @@ -26,59 +24,8 @@ static const uint8_t P2PKH_SCRIPT_POST[2] = { 0x88, 0xac }; const uint8_t *const BTC_MSG_MAGIC = (uint8_t *) "\030Bitcoin Signed Message:\n"; -enum btc_input_type { - BTC_INPUT_TYPE_LEGACY, - BTC_INPUT_TYPE_LEGACY_WITH_REDEEM, - BTC_INPUT_TYPE_P2WPKH, - BTC_INPUT_TYPE_P2WSH, -}; - -enum btc_sighash_flag { - SIGHASH_DEFAULT = 0x00, - SIGHASH_ALL = 0x01, - SIGHASH_NONE = 0x02, - SIGHASH_SINGLE = 0x03, -}; - -typedef struct { - uint8_t* script_pubkey; - size_t script_pubkey_len; - uint8_t* redeem_script; - size_t redeem_script_len; - uint8_t* witness_script; - size_t witness_script_len; - uint8_t* nonwitness_utxo; - size_t nonwitness_utxo_len; - uint8_t* amount; - uint8_t* bip32_path; - uint32_t bip32_path_len; - uint32_t master_fingerprint; - uint32_t sighash_flag; - enum btc_input_type input_type; - bool witness; - bool can_sign; -} psbt_input_data_t; - -struct btc_tx_ctx { - psbt_tx_t tx; - psbt_txin_t inputs[BTC_MAX_INPUTS]; - psbt_txout_t outputs[BTC_MAX_OUTPUTS]; - psbt_input_data_t input_data[BTC_MAX_INPUTS]; - size_t input_count; - size_t output_count; - - psbt_t psbt_out; - size_t index_in; - size_t index_out; - uint8_t hash_prevouts[SHA256_DIGEST_LENGTH]; - uint8_t hash_sequence[SHA256_DIGEST_LENGTH]; - uint8_t hash_outputs[SHA256_DIGEST_LENGTH]; - - app_err_t error; -}; - struct btc_utxo_ctx { - struct btc_tx_ctx* tx_ctx; + btc_tx_ctx_t* tx_ctx; uint32_t output_count; uint32_t input_index; }; @@ -100,7 +47,7 @@ static void core_btc_utxo_handler(psbt_txelem_t* elem) { utxo_ctx->tx_ctx->input_data[utxo_ctx->input_index].script_pubkey_len = tx_out->script_len; } -static void core_btc_psbt_rec_handler(struct btc_tx_ctx* tx_ctx, size_t index, psbt_record_t* rec) { +static void core_btc_psbt_rec_handler(btc_tx_ctx_t* tx_ctx, size_t index, psbt_record_t* rec) { if (rec->scope != PSBT_SCOPE_INPUTS) { return; } else if (index >= tx_ctx->input_count) { @@ -150,7 +97,7 @@ static void core_btc_psbt_rec_handler(struct btc_tx_ctx* tx_ctx, size_t index, p } } -static void core_btc_txelem_handler(struct btc_tx_ctx* tx_ctx, psbt_txelem_t* elem) { +static void core_btc_txelem_handler(btc_tx_ctx_t* tx_ctx, psbt_txelem_t* elem) { switch (elem->elem_type) { case PSBT_TXELEM_TX: memcpy(&tx_ctx->tx, elem->elem.tx, sizeof(psbt_tx_t)); @@ -175,7 +122,7 @@ static void core_btc_txelem_handler(struct btc_tx_ctx* tx_ctx, psbt_txelem_t* el } static void core_btc_parser_cb(psbt_elem_t* rec) { - struct btc_tx_ctx* tx_ctx = (struct btc_tx_ctx*) rec->user_data; + btc_tx_ctx_t* tx_ctx = (btc_tx_ctx_t*) rec->user_data; if (rec->type == PSBT_ELEM_RECORD) { core_btc_psbt_rec_handler(tx_ctx, rec->index, rec->elem.rec); @@ -184,7 +131,7 @@ static void core_btc_parser_cb(psbt_elem_t* rec) { } } -static app_err_t core_btc_hash_legacy(struct btc_tx_ctx* tx_ctx, size_t index, uint8_t digest[SHA256_DIGEST_LENGTH]) { +static app_err_t core_btc_hash_legacy(btc_tx_ctx_t* tx_ctx, size_t index, uint8_t digest[SHA256_DIGEST_LENGTH]) { SHA256_CTX sha256; sha256_Init(&sha256); @@ -263,7 +210,7 @@ static app_err_t core_btc_hash_legacy(struct btc_tx_ctx* tx_ctx, size_t index, u return ERR_OK; } -static app_err_t core_btc_hash_segwit(struct btc_tx_ctx* tx_ctx, size_t index, uint8_t digest[SHA256_DIGEST_LENGTH]) { +static app_err_t core_btc_hash_segwit(btc_tx_ctx_t* tx_ctx, size_t index, uint8_t digest[SHA256_DIGEST_LENGTH]) { SHA256_CTX sha256; sha256_Init(&sha256); @@ -365,7 +312,7 @@ static app_err_t core_btc_read_signature(uint8_t* data, uint8_t sighash, psbt_re return ERR_OK; } -static app_err_t core_btc_sign_input(struct btc_tx_ctx* tx_ctx, size_t index) { +static app_err_t core_btc_sign_input(btc_tx_ctx_t* tx_ctx, size_t index) { if (!tx_ctx->input_data[index].can_sign) { return ERR_OK; } @@ -419,7 +366,7 @@ static app_err_t core_btc_sign_input(struct btc_tx_ctx* tx_ctx, size_t index) { } static void core_btc_sign_handler(psbt_elem_t* rec) { - struct btc_tx_ctx* tx_ctx = (struct btc_tx_ctx*) rec->user_data; + btc_tx_ctx_t* tx_ctx = (btc_tx_ctx_t*) rec->user_data; if ((rec->type == PSBT_ELEM_TXELEM) || tx_ctx->error != ERR_OK) { return; @@ -524,7 +471,7 @@ static inline bool btc_validate_tx_hash(uint8_t* tx, size_t tx_len, uint8_t expe return memcmp(expected_hash, digest, SHA256_DIGEST_LENGTH) == 0; } -static app_err_t core_btc_validate(struct btc_tx_ctx* tx_ctx) { +static app_err_t core_btc_validate(btc_tx_ctx_t* tx_ctx) { uint32_t mfp; if (core_get_fingerprint(g_core.bip44_path, 0, &mfp) != ERR_OK) { @@ -592,12 +539,11 @@ static app_err_t core_btc_validate(struct btc_tx_ctx* tx_ctx) { return can_sign_something ? ERR_OK : ERR_MISMATCH; } -static app_err_t core_btc_confirm(struct btc_tx_ctx* tx_ctx) { - //TODO: implement - return ERR_OK; +static inline app_err_t core_btc_confirm(btc_tx_ctx_t* tx_ctx) { + return ui_display_btc_tx(tx_ctx) == CORE_EVT_UI_OK ? ERR_OK : ERR_CANCEL; } -static void core_btc_common_hashes(struct btc_tx_ctx* tx_ctx) { +static void core_btc_common_hashes(btc_tx_ctx_t* tx_ctx) { SHA256_CTX sha256; sha256_Init(&sha256); @@ -630,10 +576,10 @@ static void core_btc_common_hashes(struct btc_tx_ctx* tx_ctx) { } static app_err_t core_btc_psbt_run(const uint8_t* psbt_in, size_t psbt_len, uint8_t** psbt_out, size_t* out_len) { - struct btc_tx_ctx* tx_ctx = (struct btc_tx_ctx*) g_camera_fb[1]; - memset(tx_ctx, 0, sizeof(struct btc_tx_ctx)); - *psbt_out = &g_camera_fb[1][(sizeof(struct btc_tx_ctx) + 3) & ~0x3]; - size_t psbt_out_len = CAMERA_FB_SIZE - ((sizeof(struct btc_tx_ctx) + 3) & ~0x3); + btc_tx_ctx_t* tx_ctx = (btc_tx_ctx_t*) g_camera_fb[1]; + memset(tx_ctx, 0, sizeof(btc_tx_ctx_t)); + *psbt_out = &g_camera_fb[1][(sizeof(btc_tx_ctx_t) + 3) & ~0x3]; + size_t psbt_out_len = CAMERA_FB_SIZE - ((sizeof(btc_tx_ctx_t) + 3) & ~0x3); psbt_t psbt; psbt_init(&psbt, (uint8_t*) psbt_in, psbt_len); diff --git a/app/core/core_eth.c b/app/core/core_eth.c index a5c822f..6b33367 100644 --- a/app/core/core_eth.c +++ b/app/core/core_eth.c @@ -62,7 +62,7 @@ static app_err_t core_eth_sign(keycard_t* kc, uint8_t* out) { } static inline app_err_t core_eth_wait_tx_confirmation() { - return ui_display_tx(g_core.address, &g_core.data.eth_tx.content) == CORE_EVT_UI_OK ? ERR_OK : ERR_CANCEL; + return ui_display_eth_tx(g_core.address, &g_core.data.eth_tx.content) == CORE_EVT_UI_OK ? ERR_OK : ERR_CANCEL; } static inline app_err_t core_eth_wait_msg_confirmation(const uint8_t* msg, size_t msg_len) { diff --git a/app/tasks/ui_task.c b/app/tasks/ui_task.c index 3caaac6..4653e6f 100644 --- a/app/tasks/ui_task.c +++ b/app/tasks/ui_task.c @@ -50,8 +50,11 @@ void ui_task_entry(void* pvParameters) { case UI_CMD_MENU: g_ui_cmd.result = menu_run(); break; - case UI_CMD_DISPLAY_TXN: - g_ui_cmd.result = dialog_confirm_tx(); + case UI_CMD_DISPLAY_ETH_TX: + g_ui_cmd.result = dialog_confirm_eth_tx(); + break; + case UI_CMD_DISPLAY_BTC_TX: + g_ui_cmd.result = dialog_confirm_btc_tx(); break; case UI_CMD_DISPLAY_MSG: g_ui_cmd.result = dialog_confirm_msg(); diff --git a/app/ui/dialog.c b/app/ui/dialog.c index 232434c..66dcea9 100644 --- a/app/ui/dialog.c +++ b/app/ui/dialog.c @@ -185,8 +185,8 @@ static void dialog_calculate_fees(bignum256* fees) { bignum256 gas_amount; bignum256 prime; bn_read_be(secp256k1.prime, &prime); - bn_read_compact_be(g_ui_cmd.params.txn.tx->startgas.value, g_ui_cmd.params.txn.tx->startgas.length, &gas_amount); - bn_read_compact_be(g_ui_cmd.params.txn.tx->gasprice.value, g_ui_cmd.params.txn.tx->gasprice.length, fees); + bn_read_compact_be(g_ui_cmd.params.eth_tx.tx->startgas.value, g_ui_cmd.params.eth_tx.tx->startgas.length, &gas_amount); + bn_read_compact_be(g_ui_cmd.params.eth_tx.tx->gasprice.value, g_ui_cmd.params.eth_tx.tx->gasprice.length, fees); bn_multiply(&gas_amount, fees, &prime); } @@ -209,10 +209,10 @@ static i18n_str_id_t dialog_recognize_data(const txContent_t* tx) { } } -app_err_t dialog_confirm_tx() { +app_err_t dialog_confirm_eth_tx() { chain_desc_t chain; erc20_desc_t token; - chain.chain_id = g_ui_cmd.params.txn.tx->chainID; + chain.chain_id = g_ui_cmd.params.eth_tx.tx->chainID; uint8_t num[11]; if (eth_db_lookup_chain(&chain) != ERR_OK) { @@ -222,17 +222,17 @@ app_err_t dialog_confirm_tx() { i18n_str_id_t title; const uint8_t* to; - i18n_str_id_t data_type = dialog_recognize_data(g_ui_cmd.params.txn.tx); + i18n_str_id_t data_type = dialog_recognize_data(g_ui_cmd.params.eth_tx.tx); if (data_type == TX_DATA_ERC20) { title = TX_CONFIRM_ERC20_TITLE; token.chain = chain.chain_id; - token.addr = g_ui_cmd.params.txn.tx->destination; + token.addr = g_ui_cmd.params.eth_tx.tx->destination; - memmove((uint8_t*) g_ui_cmd.params.txn.tx->value.value, &g_ui_cmd.params.txn.tx->data[ETH_ERC20_VALUE_OFF], INT256_LENGTH); - ((txContent_t*) g_ui_cmd.params.txn.tx)->value.length = INT256_LENGTH; + memmove((uint8_t*) g_ui_cmd.params.eth_tx.tx->value.value, &g_ui_cmd.params.eth_tx.tx->data[ETH_ERC20_VALUE_OFF], INT256_LENGTH); + ((txContent_t*) g_ui_cmd.params.eth_tx.tx)->value.length = INT256_LENGTH; - to = &g_ui_cmd.params.txn.tx->data[ETH_ERC20_ADDR_OFF]; + to = &g_ui_cmd.params.eth_tx.tx->data[ETH_ERC20_ADDR_OFF]; if (eth_db_lookup_erc20(&token) != ERR_OK) { token.ticker = "???"; @@ -244,7 +244,7 @@ app_err_t dialog_confirm_tx() { title = TX_CONFIRM_TITLE; token.ticker = chain.ticker; token.decimals = 18; - to = g_ui_cmd.params.txn.tx->destination; + to = g_ui_cmd.params.eth_tx.tx->destination; } dialog_title(LSTR(title)); @@ -252,13 +252,13 @@ app_err_t dialog_confirm_tx() { screen_text_ctx_t ctx; ctx.y = TH_TITLE_HEIGHT; - dialog_address(&ctx, TX_SIGNER, ADDR_ETH, g_ui_cmd.params.txn.addr); + dialog_address(&ctx, TX_SIGNER, ADDR_ETH, g_ui_cmd.params.eth_tx.addr); dialog_address(&ctx, TX_ADDRESS, ADDR_ETH, to); dialog_chain(&ctx, chain.name); dialog_tx_data(&ctx, data_type); bignum256 data; - bn_read_compact_be(g_ui_cmd.params.txn.tx->value.value, g_ui_cmd.params.txn.tx->value.length, &data); + bn_read_compact_be(g_ui_cmd.params.eth_tx.tx->value.value, g_ui_cmd.params.eth_tx.tx->value.length, &data); dialog_amount(&ctx, TX_AMOUNT, &data, token.decimals, token.ticker); dialog_calculate_fees(&data); @@ -281,6 +281,10 @@ app_err_t dialog_confirm_tx() { } } +app_err_t dialog_confirm_btc_tx() { + return ERR_OK; +} + static void dialog_draw_message(const char* txt) { dialog_title(""); dialog_footer(TH_TITLE_HEIGHT); diff --git a/app/ui/dialog.h b/app/ui/dialog.h index 46e7156..bf6bb79 100644 --- a/app/ui/dialog.h +++ b/app/ui/dialog.h @@ -16,7 +16,8 @@ app_err_t dialog_nav_hints_colors(icons_t left, icons_t right, uint16_t bg, uint app_err_t dialog_pager(size_t page, size_t last_page); app_err_t dialog_margin(uint16_t yOff, uint16_t height); -app_err_t dialog_confirm_tx(); +app_err_t dialog_confirm_eth_tx(); +app_err_t dialog_confirm_btc_tx(); app_err_t dialog_confirm_msg(); app_err_t dialog_confirm_eip712(); diff --git a/app/ui/ui.c b/app/ui/ui.c index 54a5ace..2732f92 100644 --- a/app/ui/ui.c +++ b/app/ui/ui.c @@ -32,10 +32,16 @@ core_evt_t ui_menu(const char* title, const menu_t* menu, i18n_str_id_t* selecte return ui_signal_wait(allow_usb); } -core_evt_t ui_display_tx(const uint8_t* address, const txContent_t* tx) { - g_ui_cmd.type = UI_CMD_DISPLAY_TXN; - g_ui_cmd.params.txn.addr = address; - g_ui_cmd.params.txn.tx = tx; +core_evt_t ui_display_eth_tx(const uint8_t* address, const txContent_t* tx) { + g_ui_cmd.type = UI_CMD_DISPLAY_ETH_TX; + g_ui_cmd.params.eth_tx.addr = address; + g_ui_cmd.params.eth_tx.tx = tx; + return ui_signal_wait(0); +} + +core_evt_t ui_display_btc_tx(const btc_tx_ctx_t* tx) { + g_ui_cmd.type = UI_CMD_DISPLAY_BTC_TX; + g_ui_cmd.params.btc_tx.tx = tx; return ui_signal_wait(0); } diff --git a/app/ui/ui.h b/app/ui/ui.h index e82a443..781acea 100644 --- a/app/ui/ui.h +++ b/app/ui/ui.h @@ -3,6 +3,7 @@ #include #include "crypto/address.h" +#include "bitcoin/bitcoin.h" #include "ethereum/ethUstream.h" #include "ethereum/eip712.h" #include "menu.h" @@ -22,7 +23,8 @@ typedef enum { core_evt_t ui_qrscan(ur_type_t type, void* out); core_evt_t ui_qrscan_tx(ur_type_t* type, void* out); core_evt_t ui_menu(const char* title, const menu_t* menu, i18n_str_id_t* selected, i18n_str_id_t marked, uint8_t allow_usb); -core_evt_t ui_display_tx(const uint8_t* address, const txContent_t* tx); +core_evt_t ui_display_eth_tx(const uint8_t* address, const txContent_t* tx); +core_evt_t ui_display_btc_tx(const btc_tx_ctx_t* tx); core_evt_t ui_display_msg(addr_type_t addr_type, const uint8_t* address, const uint8_t* msg, uint32_t len); core_evt_t ui_display_eip712(const uint8_t* address, const eip712_ctx_t* eip712); core_evt_t ui_display_ur_qr(const char* title, const uint8_t* data, uint32_t len, ur_type_t type); diff --git a/app/ui/ui_internal.h b/app/ui/ui_internal.h index ff74520..17e7dae 100644 --- a/app/ui/ui_internal.h +++ b/app/ui/ui_internal.h @@ -6,6 +6,7 @@ #include "menu.h" #include "keypad/keypad.h" +#include "bitcoin/bitcoin.h" #include "core/core.h" #include "ethereum/ethUstream.h" #include "qrcode/qrcode.h" @@ -24,7 +25,8 @@ enum cmd_type { UI_CMD_INFO, UI_CMD_PROMPT, UI_CMD_MENU, - UI_CMD_DISPLAY_TXN, + UI_CMD_DISPLAY_ETH_TX, + UI_CMD_DISPLAY_BTC_TX, UI_CMD_DISPLAY_MSG, UI_CMD_DISPLAY_EIP712, UI_CMD_DISPLAY_QR, @@ -56,11 +58,15 @@ struct cmd_wrong_auth { uint8_t retries; }; -struct cmd_txn { +struct cmd_eth_txn { const uint8_t* addr; const txContent_t* tx; }; +struct cmd_btc_txn { + const btc_tx_ctx_t* tx; +}; + struct cmd_msg { addr_type_t addr_type; const uint8_t* addr; @@ -133,7 +139,8 @@ union cmd_params { struct cmd_info info; struct cmd_prompt prompt; struct cmd_wrong_auth wrong_auth; - struct cmd_txn txn; + struct cmd_eth_txn eth_tx; + struct cmd_btc_txn btc_tx; struct cmd_msg msg; struct cmd_eip712 eip712; struct cmd_qrout qrout;