1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-26 01:18:28 +00:00

rework hashing of transactions

This commit is contained in:
Pavol Rusnak 2014-12-21 19:39:20 +01:00
parent 2a2eba7de5
commit 30a55829e5
5 changed files with 118 additions and 40 deletions

View File

@ -47,6 +47,24 @@ uint32_t ser_length(uint32_t len, uint8_t *out)
return 5; return 5;
} }
uint32_t ser_length_hash(SHA256_CTX *ctx, uint32_t len)
{
if (len < 253) {
sha256_Update(ctx, (const uint8_t *)&len, 1);
return 1;
}
if (len < 0x10000) {
uint8_t d = 253;
sha256_Update(ctx, &d, 1);
sha256_Update(ctx, (const uint8_t *)&len, 2);
return 3;
}
uint8_t d = 254;
sha256_Update(ctx, &d, 1);
sha256_Update(ctx, (const uint8_t *)&len, 4);
return 5;
}
uint32_t deser_length(const uint8_t *in, uint32_t *out) uint32_t deser_length(const uint8_t *in, uint32_t *out)
{ {
if (in[0] < 253) { if (in[0] < 253) {

View File

@ -24,11 +24,14 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <secp256k1.h> #include <secp256k1.h>
#include <sha2.h>
#include <pb.h> #include <pb.h>
#include "types.pb.h" #include "types.pb.h"
uint32_t ser_length(uint32_t len, uint8_t *out); uint32_t ser_length(uint32_t len, uint8_t *out);
uint32_t ser_length_hash(SHA256_CTX *ctx, uint32_t len);
int cryptoMessageSign(const uint8_t *message, pb_size_t message_len, const uint8_t *privkey, uint8_t *signature); int cryptoMessageSign(const uint8_t *message, pb_size_t message_len, const uint8_t *privkey, uint8_t *signature);
int cryptoMessageVerify(const uint8_t *message, pb_size_t message_len, const uint8_t *address_raw, const uint8_t *signature); int cryptoMessageVerify(const uint8_t *message, pb_size_t message_len, const uint8_t *address_raw, const uint8_t *signature);

View File

@ -248,7 +248,7 @@ void signing_txack(TransactionType *tx)
send_req_2_prev_input(); send_req_2_prev_input();
return; return;
case STAGE_REQUEST_2_PREV_INPUT: case STAGE_REQUEST_2_PREV_INPUT:
if (!tx_hash_input(&tp, tx->inputs)) { if (!tx_serialize_input_hash(&tp, tx->inputs)) {
fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input"); fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input");
signing_abort(); signing_abort();
return; return;
@ -261,7 +261,7 @@ void signing_txack(TransactionType *tx)
} }
return; return;
case STAGE_REQUEST_2_PREV_OUTPUT: case STAGE_REQUEST_2_PREV_OUTPUT:
if (!tx_hash_output(&tp, tx->bin_outputs)) { if (!tx_serialize_output_hash(&tp, tx->bin_outputs)) {
fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize output"); fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize output");
signing_abort(); signing_abort();
return; return;
@ -288,7 +288,7 @@ void signing_txack(TransactionType *tx)
return; return;
case STAGE_REQUEST_3_INPUT: case STAGE_REQUEST_3_INPUT:
progress++; progress++;
if (!tx_hash_input(&tc, tx->inputs)) { if (!tx_serialize_input_hash(&tc, tx->inputs)) {
fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input"); fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input");
signing_abort(); signing_abort();
return; return;
@ -347,7 +347,7 @@ void signing_txack(TransactionType *tx)
} else { } else {
tx->inputs[0].script_sig.size = 0; tx->inputs[0].script_sig.size = 0;
} }
if (!tx_hash_input(&ti, tx->inputs)) { if (!tx_serialize_input_hash(&ti, tx->inputs)) {
fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input"); fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input");
signing_abort(); signing_abort();
return; return;
@ -406,12 +406,12 @@ void signing_txack(TransactionType *tx)
signing_abort(); signing_abort();
return; return;
} }
if (!tx_hash_output(&tc, &bin_output)) { if (!tx_serialize_output_hash(&tc, &bin_output)) {
fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize output"); fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize output");
signing_abort(); signing_abort();
return; return;
} }
if (!tx_hash_output(&ti, &bin_output)) { if (!tx_serialize_output_hash(&ti, &bin_output)) {
fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize output"); fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize output");
signing_abort(); signing_abort();
return; return;
@ -462,7 +462,7 @@ void signing_txack(TransactionType *tx)
} else { // SPENDADDRESS } else { // SPENDADDRESS
input.script_sig.size = serialize_script_sig(resp.serialized.signature.bytes, resp.serialized.signature.size, pubkey, 33, input.script_sig.bytes); input.script_sig.size = serialize_script_sig(resp.serialized.signature.bytes, resp.serialized.signature.size, pubkey, 33, input.script_sig.bytes);
} }
resp.serialized.serialized_tx.size = tx_serialize_input(&to, input.prev_hash.bytes, input.prev_index, input.script_sig.bytes, input.script_sig.size, input.sequence, resp.serialized.serialized_tx.bytes); resp.serialized.serialized_tx.size = tx_serialize_input(&to, &input, resp.serialized.serialized_tx.bytes);
if (idx1i < inputs_count - 1) { if (idx1i < inputs_count - 1) {
idx1i++; idx1i++;
send_req_1_input(); send_req_1_input();
@ -502,7 +502,7 @@ void signing_txack(TransactionType *tx)
} }
resp.has_serialized = true; resp.has_serialized = true;
resp.serialized.has_serialized_tx = true; resp.serialized.has_serialized_tx = true;
resp.serialized.serialized_tx.size = tx_serialize_output(&to, bin_output.amount, bin_output.script_pubkey.bytes, bin_output.script_pubkey.size, resp.serialized.serialized_tx.bytes); resp.serialized.serialized_tx.size = tx_serialize_output(&to, &bin_output, resp.serialized.serialized_tx.bytes);
if (idx4o < outputs_count - 1) { if (idx4o < outputs_count - 1) {
idx4o++; idx4o++;
send_req_4_output(); send_req_4_output();

View File

@ -29,6 +29,7 @@
#include "ripemd160.h" #include "ripemd160.h"
#include "base58.h" #include "base58.h"
#include "messages.pb.h" #include "messages.pb.h"
#include "types.pb.h"
uint32_t op_push(uint32_t i, uint8_t *out) { uint32_t op_push(uint32_t i, uint8_t *out) {
if (i < 0x4C) { if (i < 0x4C) {
@ -261,7 +262,13 @@ uint32_t tx_serialize_header(TxStruct *tx, uint8_t *out)
return 4 + ser_length(tx->inputs_len, out + 4); return 4 + ser_length(tx->inputs_len, out + 4);
} }
uint32_t tx_serialize_input(TxStruct *tx, uint8_t *prev_hash, uint32_t prev_index, uint8_t *script_sig, uint32_t script_sig_len, uint32_t sequence, uint8_t *out) uint32_t tx_serialize_header_hash(TxStruct *tx)
{
sha256_Update(&(tx->ctx), (const uint8_t *)&(tx->version), 4);
return 4 + ser_length_hash(&(tx->ctx), tx->inputs_len);
}
uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out)
{ {
int i; int i;
if (tx->have_inputs >= tx->inputs_len) { if (tx->have_inputs >= tx->inputs_len) {
@ -273,13 +280,39 @@ uint32_t tx_serialize_input(TxStruct *tx, uint8_t *prev_hash, uint32_t prev_inde
r += tx_serialize_header(tx, out + r); r += tx_serialize_header(tx, out + r);
} }
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
*(out + r + i) = prev_hash[31 - i]; *(out + r + i) = input->prev_hash.bytes[31 - i];
} }
r += 32; r += 32;
memcpy(out + r, &prev_index, 4); r += 4; memcpy(out + r, &input->prev_index, 4); r += 4;
r += ser_length(script_sig_len, out + r); r += ser_length(input->script_sig.size, out + r);
memcpy(out + r, script_sig, script_sig_len); r+= script_sig_len; memcpy(out + r, input->script_sig.bytes, input->script_sig.size); r += input->script_sig.size;
memcpy(out + r, &sequence, 4); r += 4; memcpy(out + r, &input->sequence, 4); r += 4;
tx->have_inputs++;
tx->size += r;
return r;
}
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;
}
uint32_t r = 0;
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 += 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;
tx->have_inputs++; tx->have_inputs++;
tx->size += r; tx->size += r;
@ -292,6 +325,11 @@ uint32_t tx_serialize_middle(TxStruct *tx, uint8_t *out)
return ser_length(tx->outputs_len, out); return ser_length(tx->outputs_len, out);
} }
uint32_t tx_serialize_middle_hash(TxStruct *tx)
{
return ser_length_hash(&(tx->ctx), tx->outputs_len);
}
uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out) uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out)
{ {
memcpy(out, &(tx->lock_time), 4); memcpy(out, &(tx->lock_time), 4);
@ -304,7 +342,19 @@ uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out)
} }
} }
uint32_t tx_serialize_output(TxStruct *tx, uint64_t amount, uint8_t *script_pubkey, uint32_t script_pubkey_len, uint8_t *out) uint32_t tx_serialize_footer_hash(TxStruct *tx)
{
sha256_Update(&(tx->ctx), (const uint8_t *)&(tx->lock_time), 4);
if (tx->add_hash_type) {
uint32_t ht = 1;
sha256_Update(&(tx->ctx), (const uint8_t *)&ht, 4);
return 8;
} else {
return 4;
}
}
uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out)
{ {
if (tx->have_inputs < tx->inputs_len) { if (tx->have_inputs < tx->inputs_len) {
// not all inputs provided // not all inputs provided
@ -318,9 +368,9 @@ uint32_t tx_serialize_output(TxStruct *tx, uint64_t amount, uint8_t *script_pubk
if (tx->have_outputs == 0) { if (tx->have_outputs == 0) {
r += tx_serialize_middle(tx, out + r); r += tx_serialize_middle(tx, out + r);
} }
memcpy(out + r, &amount, 8); r += 8; memcpy(out + r, &output->amount, 8); r += 8;
r += ser_length(script_pubkey_len, out + r); r += ser_length(output->script_pubkey.size, out + r);
memcpy(out + r, script_pubkey, script_pubkey_len); r+= script_pubkey_len; memcpy(out + r, output->script_pubkey.bytes, output->script_pubkey.size); r+= output->script_pubkey.size;
tx->have_outputs++; tx->have_outputs++;
if (tx->have_outputs == tx->outputs_len) { if (tx->have_outputs == tx->outputs_len) {
r += tx_serialize_footer(tx, out + r); r += tx_serialize_footer(tx, out + r);
@ -329,6 +379,31 @@ uint32_t tx_serialize_output(TxStruct *tx, uint64_t amount, uint8_t *script_pubk
return r; return r;
} }
uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output)
{
if (tx->have_inputs < tx->inputs_len) {
// not all inputs provided
return 0;
}
if (tx->have_outputs >= tx->outputs_len) {
// already got all outputs
return 0;
}
uint32_t r = 0;
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;
tx->have_outputs++;
if (tx->have_outputs == tx->outputs_len) {
r += tx_serialize_footer_hash(tx);
}
tx->size += r;
return r;
}
void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, bool add_hash_type) void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, bool add_hash_type)
{ {
tx->inputs_len = inputs_len; tx->inputs_len = inputs_len;
@ -342,24 +417,6 @@ void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t v
sha256_Init(&(tx->ctx)); sha256_Init(&(tx->ctx));
} }
bool tx_hash_input(TxStruct *t, TxInputType *input)
{
uint8_t buf[1024];
uint32_t r = tx_serialize_input(t, input->prev_hash.bytes, input->prev_index, input->script_sig.bytes, input->script_sig.size, input->sequence, buf);
if (!r) return false;
sha256_Update(&(t->ctx), buf, r);
return true;
}
bool tx_hash_output(TxStruct *t, TxOutputBinType *output)
{
uint8_t buf[1024];
uint32_t r = tx_serialize_output(t, output->amount, output->script_pubkey.bytes, output->script_pubkey.size, buf);
if (!r) return false;
sha256_Update(&(t->ctx), buf, r);
return true;
}
void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse) void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse)
{ {
sha256_Final(hash, &(t->ctx)); sha256_Final(hash, &(t->ctx));

View File

@ -47,12 +47,12 @@ 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_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); 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); int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm);
uint32_t tx_serialize_input(TxStruct *tx, uint8_t *prev_hash, uint32_t prev_index, uint8_t *script_sig, uint32_t script_sig_len, uint32_t sequence, uint8_t *out); uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out);
uint32_t tx_serialize_output(TxStruct *tx, uint64_t amount, uint8_t *script_pubkey, uint32_t script_pubkey_len, uint8_t *out); uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out);
void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, bool add_hash_type); void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, bool add_hash_type);
bool tx_hash_input(TxStruct *t, TxInputType *input); uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input);
bool tx_hash_output(TxStruct *t, TxOutputBinType *output); uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output);
void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse); void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse);
uint32_t transactionEstimateSize(uint32_t inputs, uint32_t outputs); uint32_t transactionEstimateSize(uint32_t inputs, uint32_t outputs);