mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-26 16:18:22 +00:00
rework hashing of transactions
This commit is contained in:
parent
2a2eba7de5
commit
30a55829e5
@ -47,6 +47,24 @@ uint32_t ser_length(uint32_t len, uint8_t *out)
|
||||
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)
|
||||
{
|
||||
if (in[0] < 253) {
|
||||
|
@ -24,11 +24,14 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <secp256k1.h>
|
||||
#include <sha2.h>
|
||||
#include <pb.h>
|
||||
#include "types.pb.h"
|
||||
|
||||
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 cryptoMessageVerify(const uint8_t *message, pb_size_t message_len, const uint8_t *address_raw, const uint8_t *signature);
|
||||
|
@ -248,7 +248,7 @@ void signing_txack(TransactionType *tx)
|
||||
send_req_2_prev_input();
|
||||
return;
|
||||
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");
|
||||
signing_abort();
|
||||
return;
|
||||
@ -261,7 +261,7 @@ void signing_txack(TransactionType *tx)
|
||||
}
|
||||
return;
|
||||
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");
|
||||
signing_abort();
|
||||
return;
|
||||
@ -288,7 +288,7 @@ void signing_txack(TransactionType *tx)
|
||||
return;
|
||||
case STAGE_REQUEST_3_INPUT:
|
||||
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");
|
||||
signing_abort();
|
||||
return;
|
||||
@ -347,7 +347,7 @@ void signing_txack(TransactionType *tx)
|
||||
} else {
|
||||
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");
|
||||
signing_abort();
|
||||
return;
|
||||
@ -406,12 +406,12 @@ void signing_txack(TransactionType *tx)
|
||||
signing_abort();
|
||||
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");
|
||||
signing_abort();
|
||||
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");
|
||||
signing_abort();
|
||||
return;
|
||||
@ -462,7 +462,7 @@ void signing_txack(TransactionType *tx)
|
||||
} else { // SPENDADDRESS
|
||||
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) {
|
||||
idx1i++;
|
||||
send_req_1_input();
|
||||
@ -502,7 +502,7 @@ void signing_txack(TransactionType *tx)
|
||||
}
|
||||
resp.has_serialized = 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) {
|
||||
idx4o++;
|
||||
send_req_4_output();
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "ripemd160.h"
|
||||
#include "base58.h"
|
||||
#include "messages.pb.h"
|
||||
#include "types.pb.h"
|
||||
|
||||
uint32_t op_push(uint32_t i, uint8_t *out) {
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
for (i = 0; i < 32; i++) {
|
||||
*(out + r + i) = prev_hash[31 - i];
|
||||
*(out + r + i) = input->prev_hash.bytes[31 - i];
|
||||
}
|
||||
r += 32;
|
||||
memcpy(out + r, &prev_index, 4); r += 4;
|
||||
r += ser_length(script_sig_len, out + r);
|
||||
memcpy(out + r, script_sig, script_sig_len); r+= script_sig_len;
|
||||
memcpy(out + r, &sequence, 4); r += 4;
|
||||
memcpy(out + r, &input->prev_index, 4); r += 4;
|
||||
r += ser_length(input->script_sig.size, out + r);
|
||||
memcpy(out + r, input->script_sig.bytes, input->script_sig.size); r += input->script_sig.size;
|
||||
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->size += r;
|
||||
@ -292,6 +325,11 @@ uint32_t tx_serialize_middle(TxStruct *tx, uint8_t *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)
|
||||
{
|
||||
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) {
|
||||
// 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) {
|
||||
r += tx_serialize_middle(tx, out + r);
|
||||
}
|
||||
memcpy(out + r, &amount, 8); r += 8;
|
||||
r += ser_length(script_pubkey_len, out + r);
|
||||
memcpy(out + r, script_pubkey, script_pubkey_len); r+= script_pubkey_len;
|
||||
memcpy(out + r, &output->amount, 8); r += 8;
|
||||
r += ser_length(output->script_pubkey.size, out + r);
|
||||
memcpy(out + r, 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(tx, out + r);
|
||||
@ -329,6 +379,31 @@ uint32_t tx_serialize_output(TxStruct *tx, uint64_t amount, uint8_t *script_pubk
|
||||
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)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
sha256_Final(hash, &(t->ctx));
|
||||
|
@ -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_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_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_output(TxStruct *tx, uint64_t amount, uint8_t *script_pubkey, uint32_t script_pubkey_len, uint8_t *out);
|
||||
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);
|
||||
|
||||
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);
|
||||
bool tx_hash_output(TxStruct *t, TxOutputBinType *output);
|
||||
uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input);
|
||||
uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output);
|
||||
void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse);
|
||||
|
||||
uint32_t transactionEstimateSize(uint32_t inputs, uint32_t outputs);
|
||||
|
Loading…
Reference in New Issue
Block a user