Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove old bitcoin input parser #608

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions apps/btc_family/btc_txn.c
Original file line number Diff line number Diff line change
Expand Up @@ -446,9 +446,6 @@ static bool fetch_valid_input(btc_query_t *query) {
// verify transaction details and discard the raw-transaction (prev_txn)
const btc_prev_txn_chunk_t *prev_txn = &(query->sign_txn.prev_txn_chunk);

btc_verify_input_t verify_input_data;
memzero(&(verify_input_data), sizeof(btc_verify_input_t));

// req prev txn chunk from host
if (!btc_get_query(query, BTC_QUERY_SIGN_TXN_TAG) ||
!check_which_request(query, BTC_SIGN_TXN_REQUEST_PREV_TXN_CHUNK_TAG)) {
Expand Down
268 changes: 0 additions & 268 deletions apps/btc_family/btc_txn_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@
#include <stdio.h>

#include "bignum.h"
#include "btc_helpers.h"
#include "btc_script.h"
#include "utils.h"

Expand Down Expand Up @@ -328,277 +327,10 @@ STATIC bool calculate_p2wpkh_digest(const btc_txn_context_t *context,
return true;
}

static void update_hash(btc_verify_input_t *verify_input_data,
const uint8_t *raw_txn_chunk,
int chunk_index,
int32_t offset) {
hash_case update = DEFAULT;

if (0 == chunk_index) {
update = FIRST_CHUNK_HASH;
}
switch (update) {
case FIRST_CHUNK_HASH: {
if (verify_input_data->is_segwit) {
sha256_Update(&(verify_input_data->sha_256_ctx), raw_txn_chunk, 4);
// skip marker and flag
sha256_Update(
&(verify_input_data->sha_256_ctx), raw_txn_chunk + 6, offset - 6);
} else {
sha256_Update(&(verify_input_data->sha_256_ctx), raw_txn_chunk, offset);
}
return;
break;
}

default: {
sha256_Update(&(verify_input_data->sha_256_ctx), raw_txn_chunk, offset);
break;
}
}
}

static void update_locktime(btc_verify_input_t *verify_input_data,
const uint8_t *raw_txn_chunk,
int chunk_index) {
if (verify_input_data->is_locktime_split) {
// last second chunk
if (chunk_index + 2 == verify_input_data->chunk_total) {
memcpy(
verify_input_data->locktime,
raw_txn_chunk + (CHUNK_SIZE - 4 - verify_input_data->size_last_chunk),
4 - verify_input_data->size_last_chunk);
return;
} else if (chunk_index + 1 == verify_input_data->chunk_total) {
memcpy(
verify_input_data->locktime + 4 - verify_input_data->size_last_chunk,
raw_txn_chunk,
verify_input_data->size_last_chunk);
verify_input_data->has_locktime = true;
return;
} else {
// wait for subsequent chunks
return;
}
} else if (chunk_index + 1 == verify_input_data->chunk_total) {
memcpy(verify_input_data->locktime,
raw_txn_chunk + verify_input_data->size_last_chunk - 4,
4);
verify_input_data->has_locktime = true;
} else {
// wait for subsequent chunks
return;
}
}

// TODO: Add chunking condition for varint decode
// refer: https://app.clickup.com/t/9002019994/PRF-7288
static int64_t varint_decode(const uint8_t *raw_txn_chunk, int32_t *offset) {
uint8_t first_byte = raw_txn_chunk[*offset];
if (first_byte < 0xFD) {
return first_byte;
} else {
// TODO: var-int varies between 1-9 bytes
// current implementation supports decoding
// upto 3 bytes only
uint8_t result[2];
memcpy(result, raw_txn_chunk + *offset + 1, 2);
*offset += 2;
return U16_READ_LE_ARRAY(result);
}
}
/*****************************************************************************
* GLOBAL FUNCTIONS
*****************************************************************************/

int btc_verify_input(const uint8_t *raw_txn_chunk,
const uint32_t chunk_index,
btc_verify_input_t *verify_input_data,
const btc_sign_txn_input_t *input) {
if (NULL == input || NULL == raw_txn_chunk ||
0 == verify_input_data->chunk_total) {
return -1;
}

int32_t offset = 0;
if (chunk_index == 0) {
// ignore network version (4-bytes), skip marker & flag (in segwit)
offset += (raw_txn_chunk[4] == 0 ? 6 : 4);
if (6 == offset) {
verify_input_data->is_segwit = true;
}

// TODO: Improve varint decode.
// size of variable containing script size and ip-count/op-count
// varies (1-9 Bytes) depending on its value.
// refer:
// https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer
verify_input_data->count =
raw_txn_chunk[offset++]; ///< store the number of inputs in the
///< raw_txn

verify_input_data->parsetype = INPUT;
sha256_Init(&(verify_input_data->sha_256_ctx));
} else {
offset += verify_input_data->prev_offset;
}
switch (verify_input_data->parsetype) {
case INPUT: {
while (verify_input_data->input_index < (verify_input_data->count) &&
INPUT == verify_input_data->parsetype) {
input_case ip_case = verify_input_data->input_parse;
switch (ip_case) {
case PREVIOUS_TX_HASH_PLUS_OP_INDEX_CASE: {
if (offset + 36 >= CHUNK_SIZE) {
verify_input_data->prev_offset = (offset + 36) - CHUNK_SIZE;
update_hash(
verify_input_data, raw_txn_chunk, chunk_index, CHUNK_SIZE);
verify_input_data->input_parse = SCRIPT_LENGTH_CASE;
return 4;
} else {
offset += 36;
}
}

case SCRIPT_LENGTH_CASE: {
int64_t script_length = varint_decode(raw_txn_chunk, &offset);
if (offset + script_length + 1 + 4 >= CHUNK_SIZE) {
verify_input_data->prev_offset =
(offset + script_length + 1 + 4) - CHUNK_SIZE;
update_hash(
verify_input_data, raw_txn_chunk, chunk_index, CHUNK_SIZE);
verify_input_data->input_parse =
PREVIOUS_TX_HASH_PLUS_OP_INDEX_CASE;
verify_input_data->input_index++;
return 4;
} else {
offset += (script_length + 1 + 4);
}
break;
}

default:
break;
}
verify_input_data->input_parse = PREVIOUS_TX_HASH_PLUS_OP_INDEX_CASE;
verify_input_data->input_index++;
}
verify_input_data->parsetype = OP_COUNT;
}

case OP_COUNT: {
if (offset + 1 >= CHUNK_SIZE) {
// reset prev offset
verify_input_data->prev_offset =
offset - CHUNK_SIZE; ///< Did not add +1 as returning back to
///< this stage to read op count
update_hash(verify_input_data, raw_txn_chunk, chunk_index, CHUNK_SIZE);
return 4;
} else {
verify_input_data->count = raw_txn_chunk[offset++];
}
verify_input_data->parsetype = OUTPUT;
verify_input_data->output_parse = VALUE_CASE;
}

case OUTPUT: {
while (verify_input_data->output_index < verify_input_data->count) {
output_case op_case = verify_input_data->output_parse;
switch (op_case) {
case VALUE_CASE: {
if (verify_input_data->output_index == input->prev_output_index) {
if (offset + 8 >= CHUNK_SIZE) {
verify_input_data->prev_offset = (offset + 8) - CHUNK_SIZE;
memcpy(verify_input_data->value,
raw_txn_chunk + offset,
CHUNK_SIZE - offset);
update_hash(
verify_input_data, raw_txn_chunk, chunk_index, CHUNK_SIZE);
verify_input_data->output_parse = VALUE_SPLIT_CASE;
verify_input_data->is_split = 1;
return 4;
} else {
memcpy(verify_input_data->value, raw_txn_chunk + offset, 8);
}
}
if (offset + 8 >= CHUNK_SIZE) {
verify_input_data->prev_offset = (offset + 8) - CHUNK_SIZE;
update_hash(
verify_input_data, raw_txn_chunk, chunk_index, CHUNK_SIZE);
verify_input_data->output_parse = SCRIPT_PUBKEY_CASE;
return 4;
} else {
offset += 8;
}
}

case VALUE_SPLIT_CASE: {
if (verify_input_data->is_split) {
memcpy(verify_input_data->value + (8 - offset),
raw_txn_chunk,
offset);
verify_input_data->output_parse = SCRIPT_PUBKEY_CASE;
verify_input_data->is_split = 0;
}
}

case SCRIPT_PUBKEY_CASE: {
if (offset + raw_txn_chunk[offset] + 1 >= CHUNK_SIZE) {
verify_input_data->prev_offset =
(offset + raw_txn_chunk[offset] + 1) - CHUNK_SIZE;
update_hash(
verify_input_data, raw_txn_chunk, chunk_index, CHUNK_SIZE);
verify_input_data->output_parse = VALUE_CASE;
verify_input_data->output_index++;
return 4;
} else {
offset += (raw_txn_chunk[offset] + 1);
}
break;
}
default:
break;
}
verify_input_data->output_parse = VALUE_CASE;
verify_input_data->output_index++;
}

verify_input_data->parsetype = LOCK_TIME;
update_hash(verify_input_data, raw_txn_chunk, chunk_index, offset);
}

case LOCK_TIME: {
update_locktime(verify_input_data, raw_txn_chunk, chunk_index);
if (false == verify_input_data->has_locktime) {
return 4;
}
sha256_Update(
&(verify_input_data->sha_256_ctx), verify_input_data->locktime, 4);
}
default:
break;
}

verify_input_data->parsetype = END;

// Finalize hashing
uint8_t hash[SHA256_DIGEST_LENGTH] = {0};
sha256_Final(&(verify_input_data->sha_256_ctx), hash);

if (U64_READ_LE_ARRAY(verify_input_data->value) == 0) {
return 1;
}
sha256_Raw(hash, sizeof(hash), hash);
// verify input txn hash
if (memcmp(hash, input->prev_txn_hash, sizeof(input->prev_txn_hash)) != 0) {
return 2;
}
if (U64_READ_LE_ARRAY(verify_input_data->value) != input->value) {
return 3;
}
return 0;
}

uint64_t get_transaction_fee_threshold(const btc_txn_context_t *txn_ctx) {
return (g_btc_app->max_fee / 1000) * (get_transaction_weight(txn_ctx) / 4);
}
Expand Down
63 changes: 0 additions & 63 deletions apps/btc_family/btc_txn_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@
* INCLUDES
*****************************************************************************/

#include "btc/sign_txn.pb.h"
#include "btc_priv.h"
#include "sha2.h"

/*****************************************************************************
* MACROS AND DEFINES
Expand All @@ -26,39 +24,6 @@
/*****************************************************************************
* TYPEDEFS
*****************************************************************************/
typedef enum parse_type { INPUT, OP_COUNT, OUTPUT, LOCK_TIME, END } parse_type;

typedef enum input_case {
PREVIOUS_TX_HASH_PLUS_OP_INDEX_CASE,
SCRIPT_LENGTH_CASE,
SEQ_CASE
} input_case;

typedef enum output_case {
VALUE_CASE,
VALUE_SPLIT_CASE,
SCRIPT_PUBKEY_CASE
} output_case;

typedef enum hash_case { FIRST_CHUNK_HASH, DEFAULT } hash_case;
typedef struct btc_verify_input {
int32_t chunk_total;
int32_t count; // count of ip/op
int32_t prev_offset; // offset to remember from prev chunk
int32_t input_index;
int32_t output_index;
SHA256_CTX sha_256_ctx;
parse_type parsetype;
input_case input_parse;
output_case output_parse;
bool is_segwit;
bool is_split;
bool has_locktime;
bool is_locktime_split;
int32_t size_last_chunk;
uint8_t value[8];
uint8_t locktime[4];
} btc_verify_input_t;

/*****************************************************************************
* EXPORTED VARIABLES
Expand All @@ -68,34 +33,6 @@ typedef struct btc_verify_input {
* GLOBAL FUNCTION PROTOTYPES
*****************************************************************************/

/**
* @brief Verifies the provided input with its related raw transaction byte
* @details The function verifies if the input details match with the details in
* the raw transaction. This is done by checking the output value against the
* specified output index in the raw transaction and then finally matching the
* specified hash with the calculated hash from the raw transactions bytes.
* To remove size limitations, the function requests the prev_txn from host
* in chunks of size CHUNK_SIZE.
*
* @param [in] raw_txn_chunk current chunk of transaction.
* @param [in] chunk_index index of current chunk.
* @param [in] verify_input_data struct to hold data and flags required by
* parser.
* @param [in] input Immutable reference to the btc_txn_input_t.
*
* @return int Result of verification, 0 if verified otherwise error status.
* @retval 0 Input verified successfully.
* @retval -1 If function parameters are invalid
* @retval 1 If specified output index (input->prev_output_index) is not present
* @retval 2 If there is a hash (input->prev_txn_hash) mismatch
* @retval 3 If there is a value (input->value) mismatch
* @retval 4 If in processing state, not all chunks parsed
*/
int btc_verify_input(const uint8_t *raw_txn_chunk,
const uint32_t chunk_index,
btc_verify_input_t *verify_input_data,
const btc_sign_txn_input_t *input);

/**
* @brief Calculates an estimated upper cap on the transaction fee.
* @details The function calculates the fee according to the assumed upper cap
Expand Down
Loading