diff --git a/firmware/signing.c b/firmware/signing.c index 3743092..cc3228e 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -50,7 +50,9 @@ static TxInputType input; static TxOutputBinType bin_output; static TxStruct to, tp, ti; static SHA256_CTX tc; -static uint8_t hash[32], hash_check[32], privkey[32], pubkey[33], sig[64]; +static SHA256_CTX hashers[2]; +static uint8_t hash_check[32], privkey[32], pubkey[33], sig[64]; +static uint8_t hash_prevouts[32], hash_sequence[32],hash_outputs[32]; static uint64_t to_spend, spending, change_spend; static uint32_t version = 1; static uint32_t lock_time = 0; @@ -273,6 +275,9 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinTyp sha256_Update(&tc, (const uint8_t *)&outputs_count, sizeof(outputs_count)); sha256_Update(&tc, (const uint8_t *)&version, sizeof(version)); sha256_Update(&tc, (const uint8_t *)&lock_time, sizeof(lock_time)); + // segwit hashes for hashPrevouts and hashSequence + sha256_Init(&hashers[0]); + sha256_Init(&hashers[1]); layoutProgressSwipe("Signing transaction", 0); @@ -326,6 +331,9 @@ void signing_txack(TransactionType *tx) } else { // InputScriptType_SPENDADDRESS multisig_fp_mismatch = true; } + // compute segwit hashPrevouts & hashSequence + tx_prevout_hash(&hashers[0], tx->inputs); + tx_sequence_hash(&hashers[1], tx->inputs); sha256_Update(&tc, (const uint8_t *)tx->inputs, sizeof(TxInputType)); memcpy(&input, tx->inputs, sizeof(TxInputType)); send_req_2_prev_meta(); @@ -399,6 +407,8 @@ void signing_txack(TransactionType *tx) if (tp.extra_data_received < tp.extra_data_len) { // still some data remanining send_req_2_prev_extradata(tp.extra_data_received, MIN(1024, tp.extra_data_len - tp.extra_data_received)); } else { + /* Check next output */ + uint8_t hash[32]; tx_hash_final(&tp, hash, true); if (memcmp(hash, input.prev_hash.bytes, 32) != 0) { fsm_sendFailure(FailureType_Failure_Other, "Encountered invalid prevhash"); @@ -409,6 +419,13 @@ void signing_txack(TransactionType *tx) idx1++; send_req_1_input(); } else { + // compute segwit hashPrevouts & hashSequence + sha256_Final(&hashers[0], hash_prevouts); + sha256_Raw(hash_prevouts, 32, hash_prevouts); + sha256_Final(&hashers[1], hash_sequence); + sha256_Raw(hash_sequence, 32, hash_sequence); + // init hashOutputs + sha256_Init(&hashers[0]); idx1 = 0; send_req_3_output(); } @@ -463,11 +480,15 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } + // compute segwit hashOuts + tx_output_hash(&hashers[0], &bin_output); sha256_Update(&tc, (const uint8_t *)&bin_output, sizeof(TxOutputBinType)); if (idx1 < outputs_count - 1) { idx1++; send_req_3_output(); } else { + sha256_Final(&hashers[0], hash_outputs); + sha256_Raw(hash_sequence, 32, hash_outputs); sha256_Final(&tc, hash_check); // check fees if (spending > to_spend) { @@ -532,6 +553,7 @@ void signing_txack(TransactionType *tx) } tx->inputs[0].script_sig.size = compile_script_multisig(&(tx->inputs[0].multisig), tx->inputs[0].script_sig.bytes); } else { // SPENDADDRESS + uint8_t hash[20]; ecdsa_get_pubkeyhash(node.public_key, hash); tx->inputs[0].script_sig.size = compile_script_sig(coin->address_type, hash, tx->inputs[0].script_sig.bytes); } @@ -580,6 +602,7 @@ void signing_txack(TransactionType *tx) idx2++; send_req_4_output(); } else { + uint8_t hash[32]; sha256_Final(&tc, hash); if (memcmp(hash, hash_check, 32) != 0) { fsm_sendFailure(FailureType_Failure_Other, "Transaction has changed during signing"); diff --git a/firmware/transaction.c b/firmware/transaction.c index fd03206..45e33cd 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -286,6 +286,31 @@ uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uin // tx methods +uint32_t tx_prevout_hash(SHA256_CTX *ctx, const TxInputType *input) +{ + int i; + for (i = 0; i < 32; i++) { + sha256_Update(ctx, &(input->prev_hash.bytes[31 - i]), 1); + } + sha256_Update(ctx, (const uint8_t *)&input->prev_index, 4); + return 36; +} + +uint32_t tx_sequence_hash(SHA256_CTX *ctx, const TxInputType *input) +{ + sha256_Update(ctx, (const uint8_t *)&input->sequence, 4); + return 4; +} + +uint32_t tx_output_hash(SHA256_CTX *ctx, const TxOutputBinType *output) +{ + uint32_t r = 0; + sha256_Update(ctx, (const uint8_t *)&output->amount, 8); r += 8; + r += ser_length_hash(ctx, output->script_pubkey.size); + sha256_Update(ctx, output->script_pubkey.bytes, output->script_pubkey.size); r+= output->script_pubkey.size; + return r; +} + uint32_t tx_serialize_header(TxStruct *tx, uint8_t *out) { memcpy(out, &(tx->version), 4); @@ -326,7 +351,6 @@ uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input) { - int i; if (tx->have_inputs >= tx->inputs_len) { // already got all inputs return 0; @@ -335,14 +359,10 @@ uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input) if (tx->have_inputs == 0) { r += tx_serialize_header_hash(tx); } - for (i = 0; i < 32; i++) { - sha256_Update(&(tx->ctx), &(input->prev_hash.bytes[31 - i]), 1); - } - r += 32; - sha256_Update(&(tx->ctx), (const uint8_t *)&input->prev_index, 4); r += 4; + r += tx_prevout_hash(&(tx->ctx), input); r += ser_length_hash(&(tx->ctx), input->script_sig.size); sha256_Update(&(tx->ctx), input->script_sig.bytes, input->script_sig.size); r += input->script_sig.size; - sha256_Update(&(tx->ctx), (const uint8_t *)&input->sequence, 4); r += 4; + r += tx_sequence_hash(&(tx->ctx), input); tx->have_inputs++; tx->size += r; @@ -423,9 +443,7 @@ uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output) if (tx->have_outputs == 0) { r += tx_serialize_middle_hash(tx); } - sha256_Update(&(tx->ctx), (const uint8_t *)&output->amount, 8); r += 8; - r += ser_length_hash(&(tx->ctx), output->script_pubkey.size); - sha256_Update(&(tx->ctx), output->script_pubkey.bytes, output->script_pubkey.size); r+= output->script_pubkey.size; + r += tx_output_hash(&(tx->ctx), output); tx->have_outputs++; if (tx->have_outputs == tx->outputs_len) { r += tx_serialize_footer_hash(tx); diff --git a/firmware/transaction.h b/firmware/transaction.h index 71ec1c1..c03b9fd 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -51,6 +51,11 @@ uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t *out); uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out); int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm); + +uint32_t tx_prevout_hash(SHA256_CTX *ctx, const TxInputType *input); +uint32_t tx_sequence_hash(SHA256_CTX *ctx, const TxInputType *input); +uint32_t tx_output_hash(SHA256_CTX *ctx, const TxOutputBinType *output); + uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out); uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out);