Skip to content
Merged
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
11 changes: 10 additions & 1 deletion apps/btc_family/btc_pub_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,16 @@ static size_t btc_get_address(const uint8_t *seed,
case NON_SEGWIT:
hdnode_get_address(&node, g_btc_app->p2pkh_addr_ver, addr, 35);
break;
// TODO: add support for taproot and segwit
case PURPOSE_SEGWIT:
ecdsa_get_address_segwit_p2sh(node.public_key,
g_btc_app->p2sh_addr_ver,
node.curve->hasher_pubkey,
node.curve->hasher_base58,
addr,
36);
break;

// TODO: add support for taproot
default:
break;
}
Expand Down
16 changes: 14 additions & 2 deletions apps/btc_family/btc_script.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,13 +239,25 @@ bool btc_check_script_address(const uint8_t *script,

uint8_t digest[HASHER_DIGEST_LENGTH] = {0};
btc_script_type_e type = btc_get_script_type(script, script_len);
if (SCRIPT_TYPE_P2PKH != type && SCRIPT_TYPE_P2WPKH != type) {
// allow only p2pkh and p2wpkh for change output
if (SCRIPT_TYPE_P2PKH != type && SCRIPT_TYPE_P2WPKH != type &&
SCRIPT_TYPE_P2SH != type) {
// allow only p2pkh and p2wpkh and p2sh-p2wpkh for change output
return false;
}
uint8_t offset = (SCRIPT_TYPE_P2PKH == type) ? 3 : 2;

hasher_Raw(HASHER_SHA2_RIPEMD, public_key, BTC_SHORT_PUB_KEY_SIZE, digest);

if (SCRIPT_TYPE_P2SH == type) {
// Compute redeemscript(P2WPKH). scriptpub of nested-segwit is hash160 of
// redeemscript
uint8_t buf[22] = {0};
buf[0] = 0; // version byte
buf[1] = 20; // push 20 bytes
memcpy(buf + 2, digest, 20);
hasher_Raw(HASHER_SHA2_RIPEMD, buf, 22, digest);
}

return (memcmp(digest, &script[offset], RIPEMD160_DIGEST_LENGTH) == 0);
}

Expand Down
21 changes: 19 additions & 2 deletions apps/btc_family/btc_txn.c
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,8 @@ static bool fetch_valid_input(btc_query_t *query) {
payload = NULL;
hoisted_query = NULL;

if ((SCRIPT_TYPE_P2PKH != type && SCRIPT_TYPE_P2WPKH != type) ||
if ((SCRIPT_TYPE_P2PKH != type && SCRIPT_TYPE_P2WPKH != type &&
SCRIPT_TYPE_P2SH != type) ||
validation_result != BTC_VALIDATE_SUCCESS) {
// input validation failed, terminate immediately
btc_send_error(ERROR_COMMON_ERROR_CORRUPT_DATA_TAG,
Expand Down Expand Up @@ -680,11 +681,27 @@ static bool sign_input(scrip_sig_t *signatures) {
status = true;
for (int idx = 0; idx < btc_txn_context->metadata.input_count; idx++) {
// generate the input digest and respective private key
status = btc_digest_input(btc_txn_context, idx, buffer);
memcpy(&t_node, &node, sizeof(HDNode));
hdnode_private_ckd(&t_node, btc_txn_context->inputs[idx].change_index);
hdnode_private_ckd(&t_node, btc_txn_context->inputs[idx].address_index);
hdnode_fill_public_key(&t_node);

// detect input type
btc_sign_txn_input_script_pub_key_t *script =
&btc_txn_context->inputs[idx].script_pub_key;
btc_script_type_e type = btc_get_script_type(script->bytes, script->size);
if (SCRIPT_TYPE_P2SH == type) {
// replace BIP16 scriptpubkey with redeemscript(P2WPKH)
uint8_t buf[22] = {0};
buf[0] = 0; // version byte
buf[1] = 20; // push 20 bytes
ecdsa_get_pubkeyhash(
t_node.public_key, t_node.curve->hasher_pubkey, buf + 2);
memcpy(btc_txn_context->inputs[idx].script_pub_key.bytes, buf, 22);
btc_txn_context->inputs[idx].script_pub_key.size = 22;
}

status = btc_digest_input(btc_txn_context, idx, buffer);
ecdsa_sign_digest(
curve, t_node.private_key, buffer, signatures[idx].bytes, NULL, NULL);
signatures[idx].size = btc_sig_to_script_sig(
Expand Down
1 change: 0 additions & 1 deletion apps/btc_family/btc_txn_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,6 @@ bool btc_digest_input(const btc_txn_context_t *context,
btc_sign_txn_input_script_pub_key_t *script =
&context->inputs[index].script_pub_key;
btc_script_type_e type = btc_get_script_type(script->bytes, script->size);

if (SCRIPT_TYPE_P2WPKH == type) {
// segwit digest calculation; could fail if segwit_cache not filled
status = calculate_p2wpkh_digest(context, index, digest);
Expand Down
187 changes: 187 additions & 0 deletions tests/apps/btc_app/btc_inputs_validator.c
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,193 @@ TEST(btc_inputs_validator_tests, btc_txn_helper_verify_input_p2wpkh_fail) {
TEST_ASSERT_EQUAL(BTC_VALIDATE_ERR_INVALID_TX_HASH, status);
}

TEST(btc_inputs_validator_tests, btc_txn_helper_verify_input_p2wpkh_in_p2sh) {
/* Test data source: Bip143
* https://blockstream.info/testnet/tx/b095225e60df2896a4e03fcc4fb2ba9622ee513f34b3e8de45c25a4793a244a2?expand
*/
uint8_t raw_txn[2000] = {0};
hex_string_to_byte_array(
"0200000000010258afb1ece76f01c24f4935f453d210518163cb1d0383eaec331b202ebe"
"b5e389"
"0000000017160014a76cad25cb569bb47305513ebedd6011dc419deeffffffff2b3682b3"
"592588"
"5001f0e321df28d4ac675a9cbbccef2a69533bea7c5e5ad2c40000000017160014a76cad"
"25cb56"
"9bb47305513ebedd6011dc419deeffffffff02941100000000000017a914bd7aabdeeef2"
"11b1bd"
"ad7218e14fea6c032101c087f22f00000000000017a914eaf97514c5ac1e41e413502e97"
"ae42eb"
"f27ace3a870247304402206e038f4712541d699697ed55efc41219df4f244fc72caa5edd"
"653837"
"f6555f6f02201cd8ea15b65fda17992abafaed86e066c3271ac16b9c46c54c2192438843"
"dd0401"
"21029f75e1ef6b04e004a308b1f59215a8a3a5b7958bbcf184cc24ba7ab6574448780248"
"304502"
"2100d15ce61648edc28b8b5a3531b80a1e8fc3b3eebe7d3fc4ca962cb04afc770dda0220"
"7c7eaf8"
"82d7fac45d2752f20e48d2f896715cbc5a3b0f5de3e19fea0da99beac0121029f75e1ef6"
"b04e004"
"a308b1f59215a8a3a5b7958bbcf184cc24ba7ab65744487800000000",
838,
raw_txn);
// only fill necessary values
btc_sign_txn_input_t input[] = {{
.value = 4500,
.prev_output_index = 0x00000000,
.script_pub_key = {.size = 23},
},
{
.value = 12274,
.prev_output_index = 0x00000001,
.script_pub_key = {.size = 23},
}};

hex_string_to_byte_array(
"b095225e60df2896a4e03fcc4fb2ba9622ee513f34b3e8de45c25a4793a244a2",
64,
input[0].prev_txn_hash);
// Reverse order of txn-id:
// A244A293475AC245DEE8B3343F51EE2296BAB24FCC3FE0A49628DF605E2295B0
cy_reverse_byte_array(input[0].prev_txn_hash, sizeof(input[0].prev_txn_hash));

hex_string_to_byte_array(
"b095225e60df2896a4e03fcc4fb2ba9622ee513f34b3e8de45c25a4793a244a2",
64,
input[1].prev_txn_hash);
// Reverse order of txn-id:
// A244A293475AC245DEE8B3343F51EE2296BAB24FCC3FE0A49628DF605E2295B0
cy_reverse_byte_array(input[1].prev_txn_hash, sizeof(input[1].prev_txn_hash));

hex_string_to_byte_array("a914bd7aabdeeef211b1bdad7218e14fea6c032101c087",
46,
input[0].script_pub_key.bytes);
hex_string_to_byte_array("a914eaf97514c5ac1e41e413502e97ae42ebf27ace3a87",
46,
input[1].script_pub_key.bytes);

data_ptr = raw_txn;
data_total_size = 838 / 2;

byte_stream_t stream = {
.stream_pointer = raw_txn,
.writer = generic_writer,
.offset = 0,
.capacity = 100,
};

btc_validation_error_e status = btc_validate_inputs(&stream, input);

TEST_ASSERT_EQUAL(BTC_VALIDATE_SUCCESS, status);

data_ptr = raw_txn;
data_total_size = 838 / 2;
global_offset = 0;

stream.stream_pointer = raw_txn;
stream.offset = 0;
stream.capacity = 100;

status = btc_validate_inputs(&stream, input + 1);

TEST_ASSERT_EQUAL(BTC_VALIDATE_SUCCESS, status);
}

TEST(btc_inputs_validator_tests,
btc_txn_helper_verify_input_p2wpkh_in_p2sh_fail) {
/* Test data source: Bip143
* https://blockstream.info/testnet/tx/b095225e60df2896a4e03fcc4fb2ba9622ee513f34b3e8de45c25a4793a244a2?expand
*/
uint8_t raw_txn[2000] = {0};
hex_string_to_byte_array(
"0200000000010258afb1ece76f01c24f4935f453d210518163cb1d0383eaec331b202ebe"
"b5e389"
"0000000017160014a76cad25cb569bb47305513ebedd6011dc419deeffffffff2b3682b3"
"592588"
"5001f0e321df28d4ac675a9cbbccef2a69533bea7c5e5ad2c40000000017160014a76cad"
"25cb56"
"9bb47305513ebedd6011dc419deeffffffff02941100000000000017a914bd7aabdeeef2"
"11b1bd"
"ad7218e14fea6c032101c087f22f00000000000017a914eaf97514c5ac1e41e413502e97"
"ae42eb"
"f27ace3a870247304402206e038f4712541d699697ed55efc41219df4f244fc72caa5edd"
"653837"
"f6555f6f02201cd8ea15b65fda17992abafaed86e066c3271ac16b9c46c54c2192438843"
"dd0401"
"21029f75e1ef6b04e004a308b1f59215a8a3a5b7958bbcf184cc24ba7ab6574448780248"
"304502"
"2100d15ce61648edc28b8b5a3531b80a1e8fc3b3eebe7d3fc4ca962cb04afc770dda0220"
"7c7eaf8"
"82d7fac45d2752f20e48d2f896715cbc5a3b0f5de3e19fea0da99beac0121029f75e1ef6"
"b04e004"
"a308b1f59215a8a3a5b7958bbcf184cc24ba7ab65744487800000000",
838,
raw_txn);
// only fill necessary values
btc_sign_txn_input_t input[] = {{
.value = 4500,
.prev_output_index = 0x00000000,
.script_pub_key = {.size = 23},
},
{
.value = 12274,
.prev_output_index = 0x00000001,
.script_pub_key = {.size = 23},
}};

hex_string_to_byte_array(
// invalid txn hash test. valid txn hash/id:
// b095225e60df2896a4e03fcc4fb2ba9622ee513f34b3e8de45c25a4793a244a2
"b095225e60df2896a4e03fcc4fb2ba9622ee513f34b3e8de45c25a4793a244a3",
64,
input[0].prev_txn_hash);
// Reverse order of txn-id:
// A344A293475AC245DEE8B3343F51EE2296BAB24FCC3FE0A49628DF605E2295B0
cy_reverse_byte_array(input[0].prev_txn_hash, sizeof(input[0].prev_txn_hash));

hex_string_to_byte_array(
// invalid txn hash test. valid txn hash/id:
// b095225e60df2896a4e03fcc4fb2ba9622ee513f34b3e8de45c25a4793a244a2
"b095225e60df2896a4e03fcc4fb2ba9622ee513f34b3e8de45c25a4793a244a3",
64,
input[1].prev_txn_hash);
// Reverse order of txn-id:
// A344A293475AC245DEE8B3343F51EE2296BAB24FCC3FE0A49628DF605E2295B0
cy_reverse_byte_array(input[1].prev_txn_hash, sizeof(input[1].prev_txn_hash));

hex_string_to_byte_array("a914bd7aabdeeef211b1bdad7218e14fea6c032101c087",
46,
input[0].script_pub_key.bytes);
hex_string_to_byte_array("a914eaf97514c5ac1e41e413502e97ae42ebf27ace3a87",
46,
input[1].script_pub_key.bytes);

data_ptr = raw_txn;
data_total_size = 838 / 2;

byte_stream_t stream = {
.stream_pointer = raw_txn,
.writer = generic_writer,
.offset = 0,
.capacity = 500,
};

btc_validation_error_e status = btc_validate_inputs(&stream, input);

TEST_ASSERT_EQUAL(BTC_VALIDATE_ERR_INVALID_TX_HASH, status);

data_ptr = raw_txn;
data_total_size = 838 / 2;
global_offset = 0;

stream.stream_pointer = raw_txn;
stream.offset = 0;
stream.capacity = 100;

status = btc_validate_inputs(&stream, input + 1);

TEST_ASSERT_EQUAL(BTC_VALIDATE_ERR_INVALID_TX_HASH, status);
}

TEST(btc_inputs_validator_tests,
btc_validate_inputs_for_a_transaction_with_witness_data) {
/* Test data source: rawTxn -
Expand Down
1 change: 1 addition & 0 deletions tests/apps/btc_app/btc_script_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@

#include "btc_helpers.h"
#include "btc_priv.h"
#include "btc_script.h"
#include "curves.h"
#include "flash_config.h"
#include "ltc_app.h"
Expand Down
Loading