diff --git a/src/address.c b/src/address.c index 55c41ab..f61a5cb 100644 --- a/src/address.c +++ b/src/address.c @@ -33,12 +33,19 @@ size_t compress_public_key(const uint8_t public_key[static 64], address_type_e address_type, - uint8_t *out) { + uint8_t *out, + size_t out_len) { size_t compressed_pub_size = 0; if (address_type == SCHNORR || address_type == P2SH) { compressed_pub_size = 32; + if (out_len < 32) { + return 0; + } memmove(out, public_key, 32); } else if (address_type == ECDSA) { + if (out_len < 33) { + return 0; + } compressed_pub_size = 33; // If Y coord is even, first byte is 0x02. if odd then 0x03 out[0] = public_key[63] % 2 == 0 ? 0x02 : 0x03; @@ -81,8 +88,10 @@ bool address_from_pubkey(const uint8_t public_key[static 64], // For schnorr, compressed public key we care about is the X coordinate // For ecdsa, compress public key is 1 byte (y-coord: 0x02 if even, 0x03 if odd) then X // coordinate - size_t compressed_pub_size = - compress_public_key(public_key, address_type, compressed_public_key); + size_t compressed_pub_size = compress_public_key(public_key, + address_type, + compressed_public_key, + sizeof(compressed_public_key)); if (compressed_pub_size == 0) { return false; diff --git a/src/address.h b/src/address.h index 18af109..afd0508 100644 --- a/src/address.h +++ b/src/address.h @@ -39,7 +39,8 @@ */ size_t compress_public_key(const uint8_t public_key[static 64], address_type_e address_type, - uint8_t *out); + uint8_t *out, + size_t out_len); /** * Convert public key to address. diff --git a/src/constants.h b/src/constants.h index 151d691..650f993 100644 --- a/src/constants.h +++ b/src/constants.h @@ -67,4 +67,5 @@ #define MESSAGE_SIGNING_KEY "PersonalMessageSigningHash" -#define MAX_OUTPUT_COUNT 2 +#define MAX_OUTPUT_COUNT 2 +#define SCRIPT_PUBLIC_KEY_BUFFER_LEN 40 diff --git a/src/crypto.c b/src/crypto.c index 53a2c72..1638126 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -92,10 +92,12 @@ int crypto_sign_transaction(void) { return error; } - calc_sighash(&G_context.tx_info.transaction, - txin, - public_key.W + 1, - G_context.tx_info.sighash); + if (!calc_sighash(&G_context.tx_info.transaction, + txin, + public_key.W + 1, + G_context.tx_info.sighash)) { + return -1; + } size_t sig_len = sizeof(G_context.tx_info.signature); error = cx_ecschnorr_sign_no_throw(&private_key, diff --git a/src/sighash.c b/src/sighash.c index 47124ac..4670d10 100644 --- a/src/sighash.c +++ b/src/sighash.c @@ -34,10 +34,7 @@ #include "globals.h" #include "./constants.h" -uint8_t outer_buffer[32] = {0}; -uint8_t inner_buffer[32] = {0}; - -static int hash_init(blake2b_state* hash, size_t size, uint8_t* key, size_t key_len) { +static bool hash_init(blake2b_state* hash, size_t size, uint8_t* key, size_t key_len) { if (key == NULL && key_len != 0) { goto err; } @@ -52,75 +49,104 @@ static int hash_init(blake2b_state* hash, size_t size, uint8_t* key, size_t key_ if (blake2b_init_key(hash, size, key, key_len) < 0) { goto err; } - return 0; + return true; err: - return -1; + return false; } -static void hash_update(blake2b_state* hash, uint8_t* data, size_t len) { - blake2b_update(hash, data, len); +static bool hash_update(blake2b_state* hash, uint8_t* data, size_t len) { + // blake2b_update currently always returns 0 + return blake2b_update(hash, data, len) == 0; } -static void hash_finalize(blake2b_state* hash, uint8_t* out) { - blake2b_final(hash, out, 32); +static bool hash_finalize(blake2b_state* hash, uint8_t* out, size_t out_len) { + if (out_len < 32) { + return false; + } + // blake2b_final returns 0 for success and -1 for any error + return blake2b_final(hash, out, 32) == 0; } -static void calc_prev_outputs_hash(transaction_t* tx, uint8_t* out_hash) { +static bool calc_prev_outputs_hash(transaction_t* tx, uint8_t* out_hash, size_t out_len) { blake2b_state inner_hash_writer; - hash_init(&inner_hash_writer, 256, (uint8_t*) SIGNING_KEY, 22); + uint8_t inner_buffer[32] = {0}; + if (!hash_init(&inner_hash_writer, 256, (uint8_t*) SIGNING_KEY, 22)) { + return false; + } for (size_t i = 0; i < tx->tx_input_len; i++) { memset(inner_buffer, 0, sizeof(inner_buffer)); write_u32_le(inner_buffer, 0, tx->tx_inputs[i].index); - hash_update(&inner_hash_writer, tx->tx_inputs[i].tx_id, 32); - hash_update(&inner_hash_writer, inner_buffer, 4); + if (!hash_update(&inner_hash_writer, tx->tx_inputs[i].tx_id, 32)) { + return false; + } + if (!hash_update(&inner_hash_writer, inner_buffer, 4)) { + return false; + } } - hash_finalize(&inner_hash_writer, out_hash); + return hash_finalize(&inner_hash_writer, out_hash, out_len); } -static void calc_sequences_hash(transaction_t* tx, uint8_t* out_hash) { +static bool calc_sequences_hash(transaction_t* tx, uint8_t* out_hash, size_t out_len) { blake2b_state inner_hash_writer; - hash_init(&inner_hash_writer, 256, (uint8_t*) SIGNING_KEY, 22); + uint8_t inner_buffer[32] = {0}; + if (!hash_init(&inner_hash_writer, 256, (uint8_t*) SIGNING_KEY, 22)) { + return false; + } for (size_t i = 0; i < tx->tx_input_len; i++) { memset(inner_buffer, 0, sizeof(inner_buffer)); write_u64_le(inner_buffer, 0, tx->tx_inputs[i].sequence); - hash_update(&inner_hash_writer, inner_buffer, 8); + if (!hash_update(&inner_hash_writer, inner_buffer, 8)) { + return false; + } memset(inner_buffer, 0, sizeof(inner_buffer)); } - hash_finalize(&inner_hash_writer, out_hash); + return hash_finalize(&inner_hash_writer, out_hash, out_len); } -static void calc_sig_op_count_hash(transaction_t* tx, uint8_t* out_hash) { +static bool calc_sig_op_count_hash(transaction_t* tx, uint8_t* out_hash, size_t out_len) { blake2b_state inner_hash_writer; - hash_init(&inner_hash_writer, 256, (uint8_t*) SIGNING_KEY, 22); + uint8_t inner_buffer[32] = {0}; + if (!hash_init(&inner_hash_writer, 256, (uint8_t*) SIGNING_KEY, 22)) { + return false; + } for (size_t i = 0; i < tx->tx_input_len; i++) { memset(inner_buffer, 1, 1); - hash_update(&inner_hash_writer, inner_buffer, 1); + if (!hash_update(&inner_hash_writer, inner_buffer, 1)) { + return false; + } memset(inner_buffer, 0, sizeof(inner_buffer)); } - hash_finalize(&inner_hash_writer, out_hash); + return hash_finalize(&inner_hash_writer, out_hash, out_len); } -static void calc_outputs_hash(transaction_t* tx, uint8_t* out_hash) { +static bool calc_outputs_hash(transaction_t* tx, uint8_t* out_hash, size_t out_len) { blake2b_state inner_hash_writer; - hash_init(&inner_hash_writer, 256, (uint8_t*) SIGNING_KEY, 22); + uint8_t inner_buffer[32] = {0}; + if (!hash_init(&inner_hash_writer, 256, (uint8_t*) SIGNING_KEY, 22)) { + return false; + } for (size_t i = 0; i < tx->tx_output_len; i++) { memset(inner_buffer, 0, sizeof(inner_buffer)); write_u64_le(inner_buffer, 0, tx->tx_outputs[i].value); - hash_update(&inner_hash_writer, inner_buffer, 8); // Write the output value + if (!hash_update(&inner_hash_writer, inner_buffer, 8)) { + // Write the output value + return false; + } memset(inner_buffer, 0, sizeof(inner_buffer)); - hash_update(&inner_hash_writer, - inner_buffer, - 2); // Write the output script version, assume 0 + if (!hash_update(&inner_hash_writer, inner_buffer, 2)) { + // Write the output script version, assume 0 + return false; + } uint8_t script_len = 0; if (tx->tx_outputs[i].script_public_key[0] == 0xaa) { @@ -137,14 +163,21 @@ static void calc_outputs_hash(transaction_t* tx, uint8_t* out_hash) { script_len); // Write the number of bytes of the script public key } - hash_update(&inner_hash_writer, inner_buffer, 8); - hash_update(&inner_hash_writer, tx->tx_outputs[i].script_public_key, script_len); + if (!hash_update(&inner_hash_writer, inner_buffer, 8)) { + return false; + } + if (!hash_update(&inner_hash_writer, tx->tx_outputs[i].script_public_key, script_len)) { + return false; + } } - hash_finalize(&inner_hash_writer, out_hash); + return hash_finalize(&inner_hash_writer, out_hash, out_len); } -static bool calc_txin_script_public_key(uint8_t* public_key, uint8_t* out_hash) { +static bool calc_txin_script_public_key(uint8_t* public_key, uint8_t* out_hash, size_t out_len) { + if (out_len < 34) { + return false; + } // Assume schnorr out_hash[0] = 0x20; memmove(out_hash + 1, public_key, 32); @@ -153,84 +186,137 @@ static bool calc_txin_script_public_key(uint8_t* public_key, uint8_t* out_hash) return true; } -void calc_sighash(transaction_t* tx, +bool calc_sighash(transaction_t* tx, transaction_input_t* txin, uint8_t* public_key, uint8_t* out_hash) { + uint8_t outer_buffer[36] = {0}; blake2b_state sighash; memset(outer_buffer, 0, sizeof(outer_buffer)); - memset(inner_buffer, 0, sizeof(inner_buffer)); - hash_init(&sighash, 256, (uint8_t*) SIGNING_KEY, 22); + if (!hash_init(&sighash, 256, (uint8_t*) SIGNING_KEY, 22)) { + return false; + } // Write version, little endian, 2 bytes write_u16_le(outer_buffer, 0, tx->version); - hash_update(&sighash, outer_buffer, 2); + if (!hash_update(&sighash, outer_buffer, 2)) { + return false; + } memset(outer_buffer, 0, sizeof(outer_buffer)); // Write previous outputs hash - calc_prev_outputs_hash(tx, outer_buffer); - hash_update(&sighash, outer_buffer, 32); + if (!calc_prev_outputs_hash(tx, outer_buffer, sizeof(outer_buffer))) { + return false; + } + if (!hash_update(&sighash, outer_buffer, 32)) { + return false; + } memset(outer_buffer, 0, sizeof(outer_buffer)); // Write sequence hash - calc_sequences_hash(tx, outer_buffer); - hash_update(&sighash, outer_buffer, 32); + if (!calc_sequences_hash(tx, outer_buffer, sizeof(outer_buffer))) { + return false; + } + if (!hash_update(&sighash, outer_buffer, 32)) { + return false; + } memset(outer_buffer, 0, sizeof(outer_buffer)); // Write sig op count hash - calc_sig_op_count_hash(tx, outer_buffer); - hash_update(&sighash, outer_buffer, 32); + if (!calc_sig_op_count_hash(tx, outer_buffer, sizeof(outer_buffer))) { + return false; + } + if (!hash_update(&sighash, outer_buffer, 32)) { + return false; + } memset(outer_buffer, 0, sizeof(outer_buffer)); // Write Hash of the outpoint - hash_update(&sighash, txin->tx_id, 32); + if (!hash_update(&sighash, txin->tx_id, 32)) { + return false; + } write_u32_le(outer_buffer, 0, txin->index); - hash_update(&sighash, outer_buffer, 4); + if (!hash_update(&sighash, outer_buffer, 4)) { + return false; + } memset(outer_buffer, 0, sizeof(outer_buffer)); - hash_update(&sighash, outer_buffer, 2); // Write input script version, assume 0 + if (!hash_update(&sighash, outer_buffer, 2)) { + // Write input script version, assume 0 + return false; + } // Write input's script_public_key. Length as uint64_t followed by script // count (1 byte) + public key (32/33 byte) + op (1 byte) uint64_t script_len = 34; write_u64_le(outer_buffer, 0, script_len); - hash_update(&sighash, outer_buffer, 8); + if (!hash_update(&sighash, outer_buffer, 8)) { + return false; + } - calc_txin_script_public_key(public_key, outer_buffer); - hash_update(&sighash, outer_buffer, script_len); + if (!calc_txin_script_public_key(public_key, outer_buffer, sizeof(outer_buffer))) { + return false; + } + if (!hash_update(&sighash, outer_buffer, script_len)) { + return false; + } memset(outer_buffer, 0, sizeof(outer_buffer)); // Write input's value write_u64_le(outer_buffer, 0, txin->value); - hash_update(&sighash, outer_buffer, 8); + if (!hash_update(&sighash, outer_buffer, 8)) { + return false; + } memset(outer_buffer, 0, sizeof(outer_buffer)); // Write input's sequence number write_u64_le(outer_buffer, 0, txin->sequence); - hash_update(&sighash, outer_buffer, 8); + if (!hash_update(&sighash, outer_buffer, 8)) { + return false; + } memset(outer_buffer, 0, sizeof(outer_buffer)); // Write sigopcount, assume 1 outer_buffer[0] = 0x01; - hash_update(&sighash, outer_buffer, 1); + if (!hash_update(&sighash, outer_buffer, 1)) { + return false; + } memset(outer_buffer, 0, sizeof(outer_buffer)); // Write outputs hash - calc_outputs_hash(tx, outer_buffer); - hash_update(&sighash, outer_buffer, 32); + if (!calc_outputs_hash(tx, outer_buffer, sizeof(outer_buffer))) { + return false; + } + if (!hash_update(&sighash, outer_buffer, 32)) { + return false; + } memset(outer_buffer, 0, sizeof(outer_buffer)); // Write last bits of data, assuming 0 - hash_update(&sighash, outer_buffer, 8); // Write locktime of 0 - hash_update(&sighash, outer_buffer, 20); // Write subnetwork Id, assume zero hash - hash_update(&sighash, outer_buffer, 8); // Write gas, assume 0 - hash_update(&sighash, outer_buffer, 32); // Write payload hash, assume 0 + if (!hash_update(&sighash, outer_buffer, 8)) { + // Write locktime of 0 + return false; + } + if (!hash_update(&sighash, outer_buffer, 20)) { + // Write subnetwork Id, assume zero hash + return false; + } + if (!hash_update(&sighash, outer_buffer, 8)) { + // Write gas, assume 0 + return false; + } + if (!hash_update(&sighash, outer_buffer, 32)) { + // Write payload hash, assume 0 + return false; + } // Write sighash type, assume SigHashAll => 0x01 outer_buffer[0] = 0x01; - hash_update(&sighash, outer_buffer, 1); + if (!hash_update(&sighash, outer_buffer, 1)) { + return false; + } - hash_finalize(&sighash, out_hash); + return hash_finalize(&sighash, out_hash, sizeof(outer_buffer)); } diff --git a/src/sighash.h b/src/sighash.h index 5743399..4313bfa 100644 --- a/src/sighash.h +++ b/src/sighash.h @@ -29,7 +29,7 @@ /** * Calculate the signature hash for the given transaction and input */ -void calc_sighash(transaction_t* tx, +bool calc_sighash(transaction_t* tx, transaction_input_t* txin, uint8_t* public_key, uint8_t* out_hash); diff --git a/src/transaction/serialize.c b/src/transaction/serialize.c index 7cdc35e..f7da3d4 100644 --- a/src/transaction/serialize.c +++ b/src/transaction/serialize.c @@ -32,7 +32,7 @@ int transaction_serialize(const transaction_t *tx, uint32_t *path, uint8_t *out, size_t out_len) { size_t offset = 0; - if (out_len < 4) { + if (out_len < 9) { return -1; } diff --git a/src/transaction/types.h b/src/transaction/types.h index 49eaed2..730793f 100644 --- a/src/transaction/types.h +++ b/src/transaction/types.h @@ -77,7 +77,8 @@ typedef struct { typedef struct { uint64_t value; - uint8_t script_public_key[40]; // In hex: 20 + public_key_hex + ac (34/35 bytes total) + uint8_t script_public_key[SCRIPT_PUBLIC_KEY_BUFFER_LEN]; // In hex: 20 + public_key_hex + ac + // (34/35 bytes total) } transaction_output_t; typedef struct { diff --git a/src/transaction/utils.c b/src/transaction/utils.c index 4a56eff..9215b8a 100644 --- a/src/transaction/utils.c +++ b/src/transaction/utils.c @@ -38,18 +38,36 @@ bool transaction_utils_check_encoding(const uint8_t* memo, uint64_t memo_len) { return true; } -void script_public_key_to_address(uint8_t* out_address, uint8_t* in_script_public_key) { +bool script_public_key_to_address(uint8_t* out_address, + size_t out_len, + uint8_t* in_script_public_key, + size_t script_len) { uint8_t public_key[64] = {0}; + + // script public keys are always at least 32 bytes. We'll check this again + // once we know more about the script + if (script_len < 32) { + return false; + } + // public script keys begin with the length, followed by the amount of data size_t first_byte = (size_t) in_script_public_key[0]; address_type_e type = SCHNORR; size_t address_len = SCHNORR_ADDRESS_LEN; if (first_byte == 0xaa) { + // In this case, script len must be at least 35 chars + if (script_len < 35) { + return false; + } type = P2SH; address_len = SCHNORR_ADDRESS_LEN; memmove(public_key, in_script_public_key + 2, 32); } else if (first_byte == 0x21) { + // In this case, script len must be at least 35 chars + if (script_len < 35) { + return false; + } // We're dealing with ECDSA instead: type = ECDSA; address_len = ECDSA_ADDRESS_LEN; @@ -62,10 +80,19 @@ void script_public_key_to_address(uint8_t* out_address, uint8_t* in_script_publi // Set the correct parity for the y-coord memset(public_key + 32, parity, 32); } else { + // In this case, script len must be at least 35 chars + if (script_len < 34) { + return false; + } memmove(public_key, in_script_public_key + 1, 32); } - address_from_pubkey(public_key, type, out_address, address_len); + // We need space to write address_len + if (out_len < address_len) { + return false; + } + + return address_from_pubkey(public_key, type, out_address, address_len); } uint64_t calc_fees(transaction_input_t* inputs, diff --git a/src/transaction/utils.h b/src/transaction/utils.h index ccc81aa..436129b 100644 --- a/src/transaction/utils.h +++ b/src/transaction/utils.h @@ -46,10 +46,15 @@ bool transaction_utils_check_encoding(const uint8_t* memo, uint64_t memo_len); * * @param[out] out_address * Pointer to the buffer to write the address to + * @param[in] out_len length of output buffer * @param[in] in_script_public_key * Pointer to the buffer to read script_public_key from + * @param[in] script_len length of script output buffer */ -void script_public_key_to_address(uint8_t* out_address, uint8_t* in_script_public_key); +void script_public_key_to_address(uint8_t* out_address, + size_t out_len, + uint8_t* in_script_public_key, + size_t script_len); /** * Calculate the fees by checking the difference between inputs and outputs diff --git a/src/ui/bagl_display.c b/src/ui/bagl_display.c index 30b58e7..30e63e9 100644 --- a/src/ui/bagl_display.c +++ b/src/ui/bagl_display.c @@ -23,9 +23,6 @@ *****************************************************************************/ #ifdef HAVE_BAGL -#pragma GCC diagnostic ignored "-Wformat-invalid-specifier" // snprintf -#pragma GCC diagnostic ignored "-Wformat-extra-args" // snprintf - #include // bool #include // memset @@ -219,7 +216,9 @@ int ui_display_transaction() { uint8_t address[ECDSA_ADDRESS_LEN] = {0}; script_public_key_to_address(address, - G_context.tx_info.transaction.tx_outputs[0].script_public_key); + sizeof(address), + G_context.tx_info.transaction.tx_outputs[0].script_public_key, + SCRIPT_PUBLIC_KEY_BUFFER_LEN); snprintf(g_address, sizeof(g_address), "%.*s", ECDSA_ADDRESS_LEN, address); g_validate_callback = &ui_action_validate_transaction; diff --git a/src/ui/nbgl_display_address.c b/src/ui/nbgl_display_address.c index decebab..cd8789f 100644 --- a/src/ui/nbgl_display_address.c +++ b/src/ui/nbgl_display_address.c @@ -23,9 +23,6 @@ *****************************************************************************/ #ifdef HAVE_NBGL -#pragma GCC diagnostic ignored "-Wformat-invalid-specifier" // snprintf -#pragma GCC diagnostic ignored "-Wformat-extra-args" // snprintf - #include // bool #include // memset diff --git a/src/ui/nbgl_display_message.c b/src/ui/nbgl_display_message.c index f6a6a17..8eb0fcf 100644 --- a/src/ui/nbgl_display_message.c +++ b/src/ui/nbgl_display_message.c @@ -23,9 +23,6 @@ *****************************************************************************/ #ifdef HAVE_NBGL -#pragma GCC diagnostic ignored "-Wformat-invalid-specifier" // snprintf -#pragma GCC diagnostic ignored "-Wformat-extra-args" // snprintf - #include // bool #include // memset diff --git a/src/ui/nbgl_display_transaction.c b/src/ui/nbgl_display_transaction.c index 06feb71..bbd925a 100755 --- a/src/ui/nbgl_display_transaction.c +++ b/src/ui/nbgl_display_transaction.c @@ -23,9 +23,6 @@ *****************************************************************************/ #ifdef HAVE_NBGL -#pragma GCC diagnostic ignored "-Wformat-invalid-specifier" // snprintf -#pragma GCC diagnostic ignored "-Wformat-extra-args" // snprintf - #include // bool #include // memset @@ -144,7 +141,9 @@ int ui_display_transaction() { uint8_t address[ECDSA_ADDRESS_LEN] = {0}; script_public_key_to_address(address, - G_context.tx_info.transaction.tx_outputs[0].script_public_key); + sizeof(address), + G_context.tx_info.transaction.tx_outputs[0].script_public_key, + SCRIPT_PUBLIC_KEY_BUFFER_LEN); snprintf(g_address, sizeof(g_address), "%.*s", ECDSA_ADDRESS_LEN, address); // Start review diff --git a/unit-tests/test_address.c b/unit-tests/test_address.c index 4b4c2c4..bd32bf1 100644 --- a/unit-tests/test_address.c +++ b/unit-tests/test_address.c @@ -118,11 +118,81 @@ static void test_invalid_type(void **state) { assert_int_equal(res, 0); } +static void test_compress_address_schnorr(void **state) { + uint8_t public_key[] = { + 0xF3, 0x80, 0x31, 0xF6, 0x1C, 0xA2, 0x3D, 0x70, 0x84, 0x4F, 0x63, 0xA4, 0x77, 0xD0, 0x7F, 0x0B, + 0x2C, 0x2D, 0xEC, 0xAB, 0x90, 0x7C, 0x2E, 0x09, 0x6E, 0x54, 0x8B, 0x0E, 0x08, 0x72, 0x1C, 0x79, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + uint8_t compressed[32] = {0}; + + size_t result = compress_public_key(public_key, SCHNORR, compressed, sizeof(compressed)); + + assert_true(result > 0); + assert_memory_equal(compressed, public_key, 32); +} + +static void test_compress_address_ecdsa(void **state) { + uint8_t public_key_even[] = { + 0xd5, 0xfd, 0xc7, 0xad, 0x11, 0xa6, 0x5d, 0x0b, 0xbe, 0x78, 0x82, 0xfc, 0x3d, 0xbc, 0x91, 0xb5, + 0x86, 0x1d, 0x18, 0x2d, 0xcc, 0xe7, 0x9f, 0x7c, 0x1b, 0xe5, 0xbf, 0xd3, 0x0a, 0x67, 0x7c, 0xd6, + 0xc5, 0x62, 0xad, 0x66, 0xab, 0xcd, 0xb1, 0xec, 0x02, 0xf3, 0xe4, 0xb0, 0x7c, 0x11, 0xbc, 0x5a, + 0x94, 0xa6, 0x85, 0xfe, 0xdb, 0x5d, 0x55, 0x87, 0x07, 0x6e, 0x48, 0xb1, 0x2d, 0xa6, 0xc2, 0x82 + }; + + uint8_t compressed_even[33] = {0}; + + size_t result_even = compress_public_key(public_key_even, ECDSA, compressed_even, sizeof(compressed_even)); + + assert_true(result_even > 0); + assert_true(compressed_even[0] == 0x02); + assert_memory_equal(compressed_even +1, public_key_even, 32); + + uint8_t public_key_odd[] = { + 0xe3, 0x10, 0x0d, 0x85, 0xef, 0xae, 0x93, 0xe0, 0xc2, 0xfc, 0x65, 0x4b, 0x2f, 0x0c, 0x33, 0x58, + 0x4f, 0x21, 0x3a, 0x3f, 0xdf, 0xfd, 0x02, 0x3c, 0x82, 0x12, 0x77, 0xb2, 0x17, 0x89, 0xe0, 0x64, + 0xe0, 0x6b, 0x45, 0x4f, 0x5c, 0xba, 0x0e, 0xff, 0x1c, 0xe8, 0x01, 0xd3, 0x83, 0x5c, 0x39, 0xec, + 0x01, 0xca, 0x94, 0x9c, 0xa8, 0x77, 0xc0, 0xb5, 0x5b, 0xbd, 0xec, 0xa8, 0xff, 0x84, 0x91, 0xd9 + }; + + uint8_t compressed_odd[33] = {0}; + + size_t result_odd = compress_public_key(public_key_odd, ECDSA, compressed_odd, sizeof(compressed_odd)); + + assert_true(result_odd > 0); + assert_true(compressed_odd[0] == 0x03); + assert_memory_equal(compressed_odd + 1, public_key_odd, 32); +} + +static void test_invalid_compress_address(void **state) { + uint8_t public_key[] = { + 0xe3, 0x10, 0x0d, 0x85, 0xef, 0xae, 0x93, 0xe0, 0xc2, 0xfc, 0x65, 0x4b, 0x2f, 0x0c, 0x33, 0x58, + 0x4f, 0x21, 0x3a, 0x3f, 0xdf, 0xfd, 0x02, 0x3c, 0x82, 0x12, 0x77, 0xb2, 0x17, 0x89, 0xe0, 0x64, + 0xe0, 0x6b, 0x45, 0x4f, 0x5c, 0xba, 0x0e, 0xff, 0x1c, 0xe8, 0x01, 0xd3, 0x83, 0x5c, 0x39, 0xec, + 0x01, 0xca, 0x94, 0x9c, 0xa8, 0x77, 0xc0, 0xb5, 0x5b, 0xbd, 0xec, 0xa8, 0xff, 0x84, 0x91, 0xd9 + }; + + uint8_t compressed_too_small_schnorr[31] = {0}; // We need 32 for valid + + size_t result_schnorr = compress_public_key(public_key, SCHNORR, compressed_too_small_schnorr, sizeof(compressed_too_small_schnorr)); + assert_true(result_schnorr == 0); + + uint8_t compressed_too_small_ecdsa[32] = {0}; // We need 33 for valid + + size_t result_ecdsa = compress_public_key(public_key, ECDSA, compressed_too_small_ecdsa, sizeof(compressed_too_small_ecdsa)); + assert_true(result_ecdsa == 0); +} + int main() { const struct CMUnitTest tests[] = {cmocka_unit_test(test_schnorr_address_from_public_key), cmocka_unit_test(test_ecdsa_address_from_public_key), cmocka_unit_test(test_p2sh_address_from_public_key), - cmocka_unit_test(test_invalid_type)}; + cmocka_unit_test(test_invalid_type), + cmocka_unit_test(test_compress_address_schnorr), + cmocka_unit_test(test_compress_address_ecdsa), + cmocka_unit_test(test_invalid_compress_address)}; return cmocka_run_group_tests(tests, NULL, NULL); } diff --git a/unit-tests/test_sighash.c b/unit-tests/test_sighash.c index 0c67887..19c74ff 100644 --- a/unit-tests/test_sighash.c +++ b/unit-tests/test_sighash.c @@ -99,7 +99,7 @@ static void test_sighash(void **state) { tx.tx_output_len = 1; uint8_t out_hash[32] = {0}; - calc_sighash(&tx, &txin, input_public_key_data, out_hash); + bool success = calc_sighash(&tx, &txin, input_public_key_data, out_hash); uint8_t res[32] = {0x7c, 0xcd, 0xa6, 0xc6, 0x4a, 0x18, 0x1e, 0x62, 0x63, 0xf0, 0xee, 0xe2, 0xed, 0xc8, 0x59, 0xdb, @@ -107,6 +107,7 @@ static void test_sighash(void **state) { 0x7d, 0xce, 0x10, 0x81, 0xbe, 0xc5, 0xba, 0xa5}; assert_memory_equal(out_hash, res, 32); + assert_true(success); } //612d56e633ee5da1caa4563c6ace0c98d3549ad4e3d2b1f1ea6810e6c34047bd @@ -151,7 +152,7 @@ static void test_sighash_zeros(void **state) { tx.tx_output_len = 1; uint8_t out_hash[32] = {0}; - calc_sighash(&tx, &txin, input_public_key_data, out_hash); + bool success = calc_sighash(&tx, &txin, input_public_key_data, out_hash); uint8_t res[32] = {0x61, 0x2d, 0x56, 0xe6, 0x33, 0xee, 0x5d, 0xa1, 0xca, 0xa4, 0x56, 0x3c, 0x6a, 0xce, 0x0c, 0x98, @@ -159,6 +160,7 @@ static void test_sighash_zeros(void **state) { 0xea, 0x68, 0x10, 0xe6, 0xc3, 0x40, 0x47, 0xbd}; assert_memory_equal(out_hash, res, 32); + assert_true(success); } int main() { diff --git a/unit-tests/test_tx_utils.c b/unit-tests/test_tx_utils.c index 0ef0b46..09b22b2 100644 --- a/unit-tests/test_tx_utils.c +++ b/unit-tests/test_tx_utils.c @@ -57,7 +57,7 @@ static void test_script_public_key_to_address(void **state) { uint8_t schnorr_address[68] = {0}; - script_public_key_to_address(schnorr_address, schnorr_spk); + script_public_key_to_address(schnorr_address, sizeof(schnorr_address), schnorr_spk, sizeof(schnorr_spk)); assert_string_equal((char *) schnorr_address, "kaspa:qrazhptjkcvrv23xz2xm8z8sfmg6jhxvmrscn7wph4k9we5tzxedwfxf0v6f8"); @@ -70,7 +70,7 @@ static void test_script_public_key_to_address(void **state) { uint8_t p2sh_address[68] = {0}; - script_public_key_to_address(p2sh_address, p2sh_spk); + script_public_key_to_address(p2sh_address, sizeof(p2sh_address), p2sh_spk, sizeof(p2sh_spk)); assert_string_equal((char *) p2sh_address, "kaspa:precqv0krj3r6uyyfa36ga7s0u9jct0v4wg8ctsfde2gkrsgwgw8jgxfzfc98"); @@ -85,7 +85,7 @@ static void test_script_public_key_to_address(void **state) { uint8_t ecdsa_even_address[70] = {0}; - script_public_key_to_address(ecdsa_even_address, ecdsa_even_spk); + script_public_key_to_address(ecdsa_even_address, sizeof(ecdsa_even_address), ecdsa_even_spk, sizeof(ecdsa_even_spk)); assert_string_equal((char *) ecdsa_even_address, "kaspa:qypdtlw845g6vhgtheug9lpahjgmtpsarqkueeul0sd7t07npfnhe4s7fd82n0v"); @@ -100,7 +100,7 @@ static void test_script_public_key_to_address(void **state) { uint8_t ecdsa_odd_address[70] = {0}; - script_public_key_to_address(ecdsa_odd_address, ecdsa_odd_spk); + script_public_key_to_address(ecdsa_odd_address, sizeof(ecdsa_odd_address), ecdsa_odd_spk, sizeof(ecdsa_odd_spk)); assert_string_equal((char *) ecdsa_odd_address, "kaspa:qyp7xyqdshh6aylqct7x2je0pse4snep8glallgz8jppyaajz7y7qeq4x79fq4z"); }