From 03a053c944a1da30d3524a6df7d6d7e698b82018 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 21 Dec 2014 00:15:46 +0100 Subject: [PATCH] implement change logic for multisig --- firmware/crypto.c | 41 +++++++++++++++++++---------------------- firmware/signing.c | 44 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 25 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index e8146f38a..bfa712275 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -285,26 +285,24 @@ int cryptoMultisigPubkeyIndex(const MultisigRedeemScriptType *multisig, const ui int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t *hash) { const uint32_t n = multisig->pubkeys_count; - const int max_pubkeys = pb_arraysize(MultisigRedeemScriptType, pubkeys); - uint8_t order[max_pubkeys], swap; + if (n > 15) { + return 0; + } + const HDNodePathType *ptr[n], *swap; uint32_t i, j; - const HDNodeType *a, *b; // check sanity for (i = 0; i < n; i++) { - order[i] = i; - a = &(multisig->pubkeys[i].node); - if (!a->has_public_key || a->public_key.size != 33) return 0; - if (a->chain_code.size != 32) return 0; + ptr[i] = &(multisig->pubkeys[i]); + if (!ptr[i]->node.has_public_key || ptr[i]->node.public_key.size != 33) return 0; + if (ptr[i]->node.chain_code.size != 32) return 0; } - // (bubble) sort according to pubkey - for (i = 0; i < n; i++) { - for (j = i; j < n; j++) { - a = &(multisig->pubkeys[order[i]].node); - b = &(multisig->pubkeys[order[j]].node); - if (memcmp(a->public_key.bytes, b->public_key.bytes, 33) > 0) { - swap = order[i]; - order[i] = order[j]; - order[j] = swap; + // minsort according to pubkey + for (i = 0; i < n - 1; i++) { + for (j = n - 1; j > i; j--) { + if (memcmp(ptr[i]->node.public_key.bytes, ptr[j]->node.public_key.bytes, 33) > 0) { + swap = ptr[i]; + ptr[i] = ptr[j]; + ptr[j] = swap; } } } @@ -312,12 +310,11 @@ int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t SHA256_CTX ctx; sha256_Init(&ctx); for (i = 0; i < n; i++) { - a = &(multisig->pubkeys[order[i]].node); - sha256_Update(&ctx, (const uint8_t *)a->depth, sizeof(uint32_t)); - sha256_Update(&ctx, (const uint8_t *)a->fingerprint, sizeof(uint32_t)); - sha256_Update(&ctx, (const uint8_t *)a->child_num, sizeof(uint32_t)); - sha256_Update(&ctx, a->chain_code.bytes, 32); - sha256_Update(&ctx, a->public_key.bytes, 33); + sha256_Update(&ctx, (const uint8_t *)&(ptr[i]->node.depth), sizeof(uint32_t)); + sha256_Update(&ctx, (const uint8_t *)&(ptr[i]->node.fingerprint), sizeof(uint32_t)); + sha256_Update(&ctx, (const uint8_t *)&(ptr[i]->node.child_num), sizeof(uint32_t)); + sha256_Update(&ctx, ptr[i]->node.chain_code.bytes, 32); + sha256_Update(&ctx, ptr[i]->node.public_key.bytes, 33); } sha256_Final(hash, &ctx); return 1; diff --git a/firmware/signing.c b/firmware/signing.c index e71b208b5..00ec93165 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -218,6 +218,8 @@ void signing_txack(TransactionType *tx) } int co; + static bool multisig_fp_set, multisig_fp_mismatch; + static uint8_t multisig_fp[32]; memset(&resp, 0, sizeof(TxRequest)); @@ -225,6 +227,8 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_1_INPUT: layoutProgress("Preparing", 1000 * progress / progress_total, progress); progress++; memcpy(&input, tx->inputs, sizeof(TxInputType)); + multisig_fp_set = false; + multisig_fp_mismatch = false; send_req_2_prev_meta(); return; case STAGE_REQUEST_2_PREV_META: @@ -277,6 +281,29 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } + if (idx1i == 0) { + if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG && + tx->inputs[0].has_multisig && !multisig_fp_mismatch) { + if (multisig_fp_set) { + uint8_t h[32]; + if (cryptoMultisigFingerprint(&(tx->inputs[0].multisig), h) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingeprint"); + signing_abort(); + return; + } + if (memcmp(multisig_fp, h, 32) != 0) { + multisig_fp_mismatch = true; + } + } else { + if (cryptoMultisigFingerprint(&(tx->inputs[0].multisig), multisig_fp) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingeprint"); + signing_abort(); + return; + } + multisig_fp_set = true; + } + } + } if (idx3i == idx1i) { memcpy(&node, root, sizeof(HDNode)); uint32_t k; @@ -324,10 +351,21 @@ void signing_txack(TransactionType *tx) layoutProgress("Signing", 1000 * progress / progress_total, progress); progress++; bool is_change = false; if (idx1i == 0) { - if (tx->outputs[0].has_multisig) { - is_change = false; // TODO: detect when not needed + if (tx->outputs[0].script_type == OutputScriptType_PAYTOMULTISIG && + tx->outputs[0].has_multisig && + multisig_fp_set && !multisig_fp_mismatch) { + uint8_t h[32]; + if (cryptoMultisigFingerprint(&(tx->outputs[0].multisig), h) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingeprint"); + signing_abort(); + return; + } + if (memcmp(multisig_fp, h, 32) == 0) { + is_change = true; + } } else - if (tx->outputs[0].address_n_count > 0) { // address_n set -> change address + if (tx->outputs[0].script_type == OutputScriptType_PAYTOADDRESS && + tx->outputs[0].address_n_count > 0) { is_change = true; } if (is_change) {