diff --git a/firmware/coins-gen.py b/firmware/coins-gen.py index 0cf4bbc..c35e7f4 100755 --- a/firmware/coins-gen.py +++ b/firmware/coins-gen.py @@ -29,6 +29,7 @@ def get_fields(coin): '%d' % coin['forkid'] if coin['forkid'] else '0', '"%s"' % coin['bech32_prefix'] if coin.get('bech32_prefix') is not None else 'NULL', '0x%08x' % (0x80000000 + coin['bip44']), + 'HASHER_SHA2', ] diff --git a/firmware/coins.h b/firmware/coins.h index bf9cd2e..a9eb89f 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -24,6 +24,7 @@ #include #include "coins_count.h" +#include "hasher.h" typedef struct _CoinInfo { const char *coin_name; @@ -43,6 +44,7 @@ typedef struct _CoinInfo { uint32_t forkid; const char *bech32_prefix; uint32_t coin_type; + HasherType hasher_type; } CoinInfo; extern const CoinInfo coins[COINS_COUNT]; diff --git a/firmware/crypto.c b/firmware/crypto.c index 391410a..17b67a4 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -54,21 +54,21 @@ uint32_t ser_length(uint32_t len, uint8_t *out) return 5; } -uint32_t ser_length_hash(SHA256_CTX *ctx, uint32_t len) +uint32_t ser_length_hash(Hasher *hasher, uint32_t len) { if (len < 253) { - sha256_Update(ctx, (const uint8_t *)&len, 1); + hasher_Update(hasher, (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); + hasher_Update(hasher, &d, 1); + hasher_Update(hasher, (const uint8_t *)&len, 2); return 3; } uint8_t d = 254; - sha256_Update(ctx, &d, 1); - sha256_Update(ctx, (const uint8_t *)&len, 4); + hasher_Update(hasher, &d, 1); + hasher_Update(hasher, (const uint8_t *)&len, 4); return 5; } diff --git a/firmware/crypto.h b/firmware/crypto.h index c77e4a9..7744c29 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -28,13 +28,14 @@ #include #include #include "coins.h" +#include "hasher.h" #include "types.pb.h" #define ser_length_size(len) ((len) < 253 ? 1 : (len) < 0x10000 ? 3 : 5) uint32_t ser_length(uint32_t len, uint8_t *out); -uint32_t ser_length_hash(SHA256_CTX *ctx, uint32_t len); +uint32_t ser_length_hash(Hasher *hasher, uint32_t len); int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); diff --git a/firmware/signing.c b/firmware/signing.c index 787eebe..5c74d3d 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -53,7 +53,7 @@ static TxRequest resp; static TxInputType input; static TxOutputBinType bin_output; static TxStruct to, tp, ti; -static SHA256_CTX hashers[3]; +static Hasher hashers[3]; static uint8_t CONFIDENTIAL privkey[32]; static uint8_t pubkey[33], sig[64]; static uint8_t hash_prevouts[32], hash_sequence[32],hash_outputs[32]; @@ -323,13 +323,11 @@ void phase1_request_next_input(void) 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); - sha256_Final(&hashers[2], hash_check); + hasher_Double(&hashers[0], hash_prevouts); + hasher_Double(&hashers[1], hash_sequence); + hasher_Final(&hashers[2], hash_check); // init hashOutputs - sha256_Init(&hashers[0]); + hasher_Reset(&hashers[0]); idx1 = 0; send_req_3_output(); } @@ -467,9 +465,9 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinInf tx_init(&to, inputs_count, outputs_count, version, lock_time, 0); // segwit hashes for hashPrevouts and hashSequence - sha256_Init(&hashers[0]); - sha256_Init(&hashers[1]); - sha256_Init(&hashers[2]); + hasher_Init(&hashers[0], coin->hasher_type); + hasher_Init(&hashers[1], coin->hasher_type); + hasher_Init(&hashers[2], coin->hasher_type); layoutProgressSwipe(_("Signing transaction"), 0); @@ -507,7 +505,7 @@ static bool signing_check_input(TxInputType *txinput) { tx_sequence_hash(&hashers[1], txinput); // hash prevout and script type to check it later (relevant for fee computation) tx_prevout_hash(&hashers[2], txinput); - sha256_Update(&hashers[2], &txinput->script_type, sizeof(&txinput->script_type)); + hasher_Update(&hashers[2], &txinput->script_type, sizeof(&txinput->script_type)); return true; } @@ -638,8 +636,7 @@ static void phase1_request_next_output(void) { idx1++; send_req_3_output(); } else { - sha256_Final(&hashers[0], hash_outputs); - sha256_Raw(hash_outputs, 32, hash_outputs); + hasher_Double(&hashers[0], hash_outputs); if (!signing_check_fee()) { return; } @@ -653,19 +650,18 @@ static void phase1_request_next_output(void) { static void signing_hash_bip143(const TxInputType *txinput, uint8_t *hash) { uint32_t hash_type = signing_hash_type(); - sha256_Init(&hashers[0]); - sha256_Update(&hashers[0], (const uint8_t *)&version, 4); - sha256_Update(&hashers[0], hash_prevouts, 32); - sha256_Update(&hashers[0], hash_sequence, 32); + hasher_Reset(&hashers[0]); + hasher_Update(&hashers[0], (const uint8_t *)&version, 4); + hasher_Update(&hashers[0], hash_prevouts, 32); + hasher_Update(&hashers[0], hash_sequence, 32); tx_prevout_hash(&hashers[0], txinput); tx_script_hash(&hashers[0], txinput->script_sig.size, txinput->script_sig.bytes); - sha256_Update(&hashers[0], (const uint8_t*) &txinput->amount, 8); + hasher_Update(&hashers[0], (const uint8_t*) &txinput->amount, 8); tx_sequence_hash(&hashers[0], txinput); - sha256_Update(&hashers[0], hash_outputs, 32); - sha256_Update(&hashers[0], (const uint8_t*) &lock_time, 4); - sha256_Update(&hashers[0], (const uint8_t*) &hash_type, 4); - sha256_Final(&hashers[0], hash); - sha256_Raw(hash, 32, hash); + hasher_Update(&hashers[0], hash_outputs, 32); + hasher_Update(&hashers[0], (const uint8_t*) &lock_time, 4); + hasher_Update(&hashers[0], (const uint8_t*) &hash_type, 4); + hasher_Double(&hashers[0], hash); } static bool signing_sign_hash(TxInputType *txinput, const uint8_t* private_key, const uint8_t *public_key, const uint8_t *hash) { @@ -705,8 +701,7 @@ static bool signing_sign_hash(TxInputType *txinput, const uint8_t* private_key, static bool signing_sign_input(void) { uint8_t hash[32]; - sha256_Final(&hashers[0], hash); - sha256_Raw(hash, 32, hash); + hasher_Double(&hashers[0], hash); if (memcmp(hash, hash_outputs, 32) != 0) { fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); @@ -714,7 +709,7 @@ static bool signing_sign_input(void) { } uint32_t hash_type = signing_hash_type(); - sha256_Update(&ti.ctx, (const uint8_t *)&hash_type, 4); + hasher_Update(&ti.hasher, (const uint8_t *)&hash_type, 4); tx_hash_final(&ti, hash, false); resp.has_serialized = true; if (!signing_sign_hash(&input, privkey, pubkey, hash)) @@ -963,11 +958,11 @@ void signing_txack(TransactionType *tx) progress = 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); if (idx2 == 0) { tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0); - sha256_Init(&hashers[0]); + hasher_Reset(&hashers[0]); } // check prevouts and script type tx_prevout_hash(&hashers[0], tx->inputs); - sha256_Update(&hashers[0], &tx->inputs[0].script_type, sizeof(&tx->inputs[0].script_type)); + hasher_Update(&hashers[0], &tx->inputs[0].script_type, sizeof(&tx->inputs[0].script_type)); if (idx2 == idx1) { if (!compile_input_script_sig(&tx->inputs[0])) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); @@ -995,13 +990,13 @@ void signing_txack(TransactionType *tx) send_req_4_input(); } else { uint8_t hash[32]; - sha256_Final(&hashers[0], hash); + hasher_Final(&hashers[0], hash); if (memcmp(hash, hash_check, 32) != 0) { fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); return; } - sha256_Init(&hashers[0]); + hasher_Reset(&hashers[0]); idx2 = 0; send_req_4_output(); } @@ -1096,7 +1091,7 @@ void signing_txack(TransactionType *tx) tx->inputs[0].script_sig.bytes[1] = 0x00; // witness 0 script tx->inputs[0].script_sig.bytes[2] = 0x20; // push 32 bytes (digest) // compute digest of multisig script - if (!compile_script_multisig_hash(&tx->inputs[0].multisig, tx->inputs[0].script_sig.bytes + 3)) { + if (!compile_script_multisig_hash(&tx->inputs[0].multisig, coin->hasher_type, tx->inputs[0].script_sig.bytes + 3)) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); signing_abort(); return; diff --git a/firmware/signing.h b/firmware/signing.h index 012ac66..e4ee8c5 100644 --- a/firmware/signing.h +++ b/firmware/signing.h @@ -24,6 +24,7 @@ #include #include "bip32.h" #include "coins.h" +#include "hasher.h" #include "types.pb.h" void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinInfo *_coin, const HDNode *_root, uint32_t _version, uint32_t _lock_time); diff --git a/firmware/transaction.c b/firmware/transaction.c index a5740e8..ec2ed1d 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -97,7 +97,7 @@ bool compute_address(const CoinInfo *coin, if (cryptoMultisigPubkeyIndex(multisig, node->public_key) < 0) { return 0; } - if (compile_script_multisig_hash(multisig, digest) == 0) { + if (compile_script_multisig_hash(multisig, coin->hasher_type, digest) == 0) { return 0; } if (script_type == InputScriptType_SPENDWITNESS) { @@ -119,7 +119,7 @@ bool compute_address(const CoinInfo *coin, raw[0] = 0; // push version raw[1] = 32; // push 32 bytes memcpy(raw+2, digest, 32); // push hash - sha256_Raw(raw, 34, digest); + hasher_Raw(coin->hasher_type, raw, 34, digest); prelen = address_prefix_bytes_len(coin->address_type_p2sh); address_write_prefix_bytes(coin->address_type_p2sh, raw); ripemd160(digest, 32, raw + prelen); @@ -305,7 +305,7 @@ uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8 return r; } -uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, uint8_t *hash) +uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, HasherType hasher_type, uint8_t *hash) { if (!multisig->has_m) return 0; const uint32_t m = multisig->m; @@ -313,22 +313,22 @@ uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, if (m < 1 || m > 15) return 0; if (n < 1 || n > 15) return 0; - SHA256_CTX ctx; - sha256_Init(&ctx); + Hasher hasher; + hasher_Init(&hasher, hasher_type); uint8_t d[2]; - d[0] = 0x50 + m; sha256_Update(&ctx, d, 1); + d[0] = 0x50 + m; hasher_Update(&hasher, d, 1); for (uint32_t i = 0; i < n; i++) { - d[0] = 33; sha256_Update(&ctx, d, 1); // OP_PUSH 33 + d[0] = 33; hasher_Update(&hasher, d, 1); // OP_PUSH 33 const uint8_t *pubkey = cryptoHDNodePathToPubkey(&(multisig->pubkeys[i])); if (!pubkey) return 0; - sha256_Update(&ctx, pubkey, 33); + hasher_Update(&hasher, pubkey, 33); } d[0] = 0x50 + n; d[1] = 0xAE; - sha256_Update(&ctx, d, 2); + hasher_Update(&hasher, d, 2); - sha256_Final(&ctx, hash); + hasher_Final(&hasher, hash); return 1; } @@ -367,33 +367,33 @@ uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uin // tx methods -uint32_t tx_prevout_hash(SHA256_CTX *ctx, const TxInputType *input) +uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input) { for (int i = 0; i < 32; i++) { - sha256_Update(ctx, &(input->prev_hash.bytes[31 - i]), 1); + hasher_Update(hasher, &(input->prev_hash.bytes[31 - i]), 1); } - sha256_Update(ctx, (const uint8_t *)&input->prev_index, 4); + hasher_Update(hasher, (const uint8_t *)&input->prev_index, 4); return 36; } -uint32_t tx_script_hash(SHA256_CTX *ctx, uint32_t size, const uint8_t *data) +uint32_t tx_script_hash(Hasher *hasher, uint32_t size, const uint8_t *data) { - int r = ser_length_hash(ctx, size); - sha256_Update(ctx, data, size); + int r = ser_length_hash(hasher, size); + hasher_Update(hasher, data, size); return r + size; } -uint32_t tx_sequence_hash(SHA256_CTX *ctx, const TxInputType *input) +uint32_t tx_sequence_hash(Hasher *hasher, const TxInputType *input) { - sha256_Update(ctx, (const uint8_t *)&input->sequence, 4); + hasher_Update(hasher, (const uint8_t *)&input->sequence, 4); return 4; } -uint32_t tx_output_hash(SHA256_CTX *ctx, const TxOutputBinType *output) +uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output) { uint32_t r = 0; - sha256_Update(ctx, (const uint8_t *)&output->amount, 8); r += 8; - r += tx_script_hash(ctx, output->script_pubkey.size, output->script_pubkey.bytes); + hasher_Update(hasher, (const uint8_t *)&output->amount, 8); r += 8; + r += tx_script_hash(hasher, output->script_pubkey.size, output->script_pubkey.bytes); return r; } @@ -418,12 +418,12 @@ uint32_t tx_serialize_header(TxStruct *tx, uint8_t *out) uint32_t tx_serialize_header_hash(TxStruct *tx) { int r = 4; - sha256_Update(&(tx->ctx), (const uint8_t *)&(tx->version), 4); + hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->version), 4); if (tx->is_segwit) { - sha256_Update(&(tx->ctx), segwit_header, 2); + hasher_Update(&(tx->hasher), segwit_header, 2); r += 2; } - return r + ser_length_hash(&(tx->ctx), tx->inputs_len); + return r + ser_length_hash(&(tx->hasher), tx->inputs_len); } uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out) @@ -460,9 +460,9 @@ uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input) if (tx->have_inputs == 0) { r += tx_serialize_header_hash(tx); } - r += tx_prevout_hash(&(tx->ctx), input); - r += tx_script_hash(&(tx->ctx), input->script_sig.size, input->script_sig.bytes); - r += tx_sequence_hash(&(tx->ctx), input); + r += tx_prevout_hash(&(tx->hasher), input); + r += tx_script_hash(&(tx->hasher), input->script_sig.size, input->script_sig.bytes); + r += tx_sequence_hash(&(tx->hasher), input); tx->have_inputs++; tx->size += r; @@ -477,7 +477,7 @@ uint32_t tx_serialize_middle(TxStruct *tx, uint8_t *out) uint32_t tx_serialize_middle_hash(TxStruct *tx) { - return ser_length_hash(&(tx->ctx), tx->outputs_len); + return ser_length_hash(&(tx->hasher), tx->outputs_len); } uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out) @@ -488,7 +488,7 @@ uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out) uint32_t tx_serialize_footer_hash(TxStruct *tx) { - sha256_Update(&(tx->ctx), (const uint8_t *)&(tx->lock_time), 4); + hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->lock_time), 4); return 4; } @@ -531,7 +531,7 @@ uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output) if (tx->have_outputs == 0) { r += tx_serialize_middle_hash(tx); } - r += tx_output_hash(&(tx->ctx), output); + r += tx_output_hash(&(tx->hasher), output); tx->have_outputs++; if (tx->have_outputs == tx->outputs_len && !tx->is_segwit) { @@ -555,7 +555,7 @@ uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_ // we are receiving too much data return 0; } - sha256_Update(&(tx->ctx), data, datalen); + hasher_Update(&(tx->hasher), data, datalen); tx->extra_data_received += datalen; tx->size += datalen; return datalen; @@ -573,13 +573,12 @@ void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t v tx->extra_data_received = 0; tx->size = 0; tx->is_segwit = false; - sha256_Init(&(tx->ctx)); + hasher_Init(&(tx->hasher), HASHER_SHA2); } void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse) { - sha256_Final(&(t->ctx), hash); - sha256_Raw(hash, 32, hash); + hasher_Double(&(t->hasher), hash); if (!reverse) return; for (uint8_t i = 0; i < 16; i++) { uint8_t k = hash[31 - i]; diff --git a/firmware/transaction.h b/firmware/transaction.h index d802ece..2e9230d 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -25,6 +25,7 @@ #include "sha2.h" #include "bip32.h" #include "coins.h" +#include "hasher.h" #include "types.pb.h" typedef struct { @@ -43,21 +44,21 @@ typedef struct { uint32_t size; - SHA256_CTX ctx; + Hasher hasher; } TxStruct; bool compute_address(const CoinInfo *coin, InputScriptType script_type, const HDNode *node, bool has_multisig, const MultisigRedeemScriptType *multisig, char address[MAX_ADDR_SIZE]); uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out); uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out); -uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, uint8_t *hash); +uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, HasherType hasher_type, uint8_t *hash); uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t sighash, uint8_t *out); uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t sighash, uint8_t *out); int compile_output(const CoinInfo *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_script_hash(SHA256_CTX *ctx, uint32_t size, const uint8_t *data); -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_prevout_hash(Hasher *hasher, const TxInputType *input); +uint32_t tx_script_hash(Hasher *hasher, uint32_t size, const uint8_t *data); +uint32_t tx_sequence_hash(Hasher *hasher, const TxInputType *input); +uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output); uint32_t tx_serialize_script(uint32_t size, const uint8_t *data, uint8_t *out); uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out);