stub btc tx confirmation

This commit is contained in:
Michele Balistreri 2024-07-24 10:03:41 +02:00
parent 9b4769a9c4
commit 2a30adddd5
No known key found for this signature in database
GPG Key ID: E9567DA33A4F791A
9 changed files with 126 additions and 95 deletions

62
app/bitcoin/bitcoin.h Normal file
View File

@ -0,0 +1,62 @@
#ifndef __BITCOIN__
#define __BITCOIN__
#include <stddef.h>
#include <stdbool.h>
#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

View File

@ -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);

View File

@ -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) {

View File

@ -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();

View File

@ -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);

View File

@ -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();

View File

@ -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);
}

View File

@ -3,6 +3,7 @@
#include <stdint.h>
#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);

View File

@ -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;