From 19c7c8bc3b76a9489b9a5cce5d9b69d60b1f20cb Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 4 Feb 2019 01:26:26 +0100 Subject: [PATCH] signing: implemented simplified API for MultisigRedeemScriptType If address_n is the same for all nodes in the multisig, provide it just once and supply nodes directly (not in the HDNodePathType structure) --- firmware/crypto.c | 87 ++++++++++++++++++++++++++++++------------ firmware/crypto.h | 4 +- firmware/transaction.c | 16 ++++---- 3 files changed, 73 insertions(+), 34 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 68019cb5aa..f71b093321 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -334,28 +334,55 @@ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_le } */ -uint8_t *cryptoHDNodePathToPubkey(const CoinInfo *coin, const HDNodePathType *hdnodepath) +const HDNode *cryptoMultisigPubkey(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint32_t index) { - if (!hdnodepath->node.has_public_key || hdnodepath->node.public_key.size != 33) return 0; + const HDNodeType *node_ptr; + const uint32_t *address_n; + uint32_t address_n_count; + if (multisig->nodes_count) { // use multisig->nodes + if (index >= multisig->nodes_count) { + return 0; + } + node_ptr = &(multisig->nodes[index]); + address_n = multisig->address_n; + address_n_count = multisig->address_n_count; + } else + if (multisig->pubkeys_count) { // use multisig->pubkeys + if (index >= multisig->pubkeys_count) { + return 0; + } + node_ptr = &(multisig->pubkeys[index].node); + address_n = multisig->pubkeys[index].address_n; + address_n_count = multisig->pubkeys[index].address_n_count; + } else { + return 0; + } + if (node_ptr->chain_code.size != 32) return 0; + if (!node_ptr->has_public_key || node_ptr->public_key.size != 33) return 0; static HDNode node; - if (hdnode_from_xpub(hdnodepath->node.depth, hdnodepath->node.child_num, hdnodepath->node.chain_code.bytes, hdnodepath->node.public_key.bytes, coin->curve_name, &node) == 0) { + if (!hdnode_from_xpub(node_ptr->depth, node_ptr->child_num, node_ptr->chain_code.bytes, node_ptr->public_key.bytes, coin->curve_name, &node)) { return 0; } layoutProgressUpdate(true); - for (uint32_t i = 0; i < hdnodepath->address_n_count; i++) { - if (hdnode_public_ckd(&node, hdnodepath->address_n[i]) == 0) { + for (uint32_t i = 0; i < address_n_count; i++) { + if (!hdnode_public_ckd(&node, address_n[i])) { return 0; } layoutProgressUpdate(true); } - return node.public_key; + return &node; +} + +uint32_t cryptoMultisigPubkeyCount(const MultisigRedeemScriptType *multisig) +{ + return multisig->nodes_count ? multisig->nodes_count : multisig->pubkeys_count; } int cryptoMultisigPubkeyIndex(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, const uint8_t *pubkey) { - for (size_t i = 0; i < multisig->pubkeys_count; i++) { - const uint8_t *node_pubkey = cryptoHDNodePathToPubkey(coin, &(multisig->pubkeys[i])); - if (node_pubkey && memcmp(node_pubkey, pubkey, 33) == 0) { + for (size_t i = 0; i < cryptoMultisigPubkeyCount(multisig); i++) { + const HDNode *pubnode = cryptoMultisigPubkey(coin, multisig, i); + if (pubnode && memcmp(pubnode->public_key, pubkey, 33) == 0) { return i; } } @@ -364,25 +391,35 @@ int cryptoMultisigPubkeyIndex(const CoinInfo *coin, const MultisigRedeemScriptTy int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t *hash) { - static const HDNodePathType *ptr[15], *swap; - const uint32_t n = multisig->pubkeys_count; + static const HDNodeType *pubnodes[15], *swap; + const uint32_t n = cryptoMultisigPubkeyCount(multisig); if (n < 1 || n > 15) { return 0; } - // check sanity - if (!multisig->has_m || multisig->m < 1 || multisig->m > 15) return 0; + if (!multisig->has_m || multisig->m < 1 || multisig->m > 15) { + return 0; + } for (uint32_t i = 0; i < n; i++) { - 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; + if (multisig->nodes_count) { // use multisig->nodes + pubnodes[i] = &(multisig->nodes[i]); + } else + if (multisig->pubkeys_count) { // use multisig->pubkeys + pubnodes[i] = &(multisig->pubkeys[i].node); + } else { + return 0; + } + } + for (uint32_t i = 0; i < n; i++) { + if (!pubnodes[i]->has_public_key || pubnodes[i]->public_key.size != 33) return 0; + if (pubnodes[i]->chain_code.size != 32) return 0; } // minsort according to pubkey for (uint32_t i = 0; i < n - 1; i++) { for (uint32_t 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; + if (memcmp(pubnodes[i]->public_key.bytes, pubnodes[j]->public_key.bytes, 33) > 0) { + swap = pubnodes[i]; + pubnodes[i] = pubnodes[j]; + pubnodes[j] = swap; } } } @@ -391,11 +428,11 @@ int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t sha256_Init(&ctx); sha256_Update(&ctx, (const uint8_t *)&(multisig->m), sizeof(uint32_t)); for (uint32_t i = 0; i < n; i++) { - 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_Update(&ctx, (const uint8_t *)&(pubnodes[i]->depth), sizeof(uint32_t)); + sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->fingerprint), sizeof(uint32_t)); + sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->child_num), sizeof(uint32_t)); + sha256_Update(&ctx, pubnodes[i]->chain_code.bytes, 32); + sha256_Update(&ctx, pubnodes[i]->public_key.bytes, 33); } sha256_Update(&ctx, (const uint8_t *)&n, sizeof(uint32_t)); sha256_Final(&ctx, hash); diff --git a/firmware/crypto.h b/firmware/crypto.h index feb1c4c370..f8d77c9205 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -52,7 +52,9 @@ int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_siz int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_len, const uint8_t *hmac, size_t hmac_len, const uint8_t *privkey, uint8_t *msg, size_t *msg_len, bool *display_only, bool *signing, uint8_t *address_raw); */ -uint8_t *cryptoHDNodePathToPubkey(const CoinInfo *coin, const HDNodePathType *hdnodepath); +const HDNode *cryptoMultisigPubkey(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint32_t index); + +uint32_t cryptoMultisigPubkeyCount(const MultisigRedeemScriptType *multisig); int cryptoMultisigPubkeyIndex(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, const uint8_t *pubkey); diff --git a/firmware/transaction.c b/firmware/transaction.c index f4a0845c6b..fbfd5c2f72 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -340,7 +340,7 @@ uint32_t compile_script_multisig(const CoinInfo *coin, const MultisigRedeemScrip { if (!multisig->has_m) return 0; const uint32_t m = multisig->m; - const uint32_t n = multisig->pubkeys_count; + const uint32_t n = cryptoMultisigPubkeyCount(multisig); if (m < 1 || m > 15) return 0; if (n < 1 || n > 15) return 0; uint32_t r = 0; @@ -348,9 +348,9 @@ uint32_t compile_script_multisig(const CoinInfo *coin, const MultisigRedeemScrip out[r] = 0x50 + m; r++; for (uint32_t i = 0; i < n; i++) { out[r] = 33; r++; // OP_PUSH 33 - const uint8_t *pubkey = cryptoHDNodePathToPubkey(coin, &(multisig->pubkeys[i])); - if (!pubkey) return 0; - memcpy(out + r, pubkey, 33); r += 33; + const HDNode *pubnode = cryptoMultisigPubkey(coin, multisig, i); + if (!pubnode) return 0; + memcpy(out + r, pubnode->public_key, 33); r += 33; } out[r] = 0x50 + n; r++; out[r] = 0xAE; r++; // OP_CHECKMULTISIG @@ -364,7 +364,7 @@ uint32_t compile_script_multisig_hash(const CoinInfo *coin, const MultisigRedeem { if (!multisig->has_m) return 0; const uint32_t m = multisig->m; - const uint32_t n = multisig->pubkeys_count; + const uint32_t n = cryptoMultisigPubkeyCount(multisig); if (m < 1 || m > 15) return 0; if (n < 1 || n > 15) return 0; @@ -375,9 +375,9 @@ uint32_t compile_script_multisig_hash(const CoinInfo *coin, const MultisigRedeem d[0] = 0x50 + m; hasher_Update(&hasher, d, 1); for (uint32_t i = 0; i < n; i++) { d[0] = 33; hasher_Update(&hasher, d, 1); // OP_PUSH 33 - const uint8_t *pubkey = cryptoHDNodePathToPubkey(coin, &(multisig->pubkeys[i])); - if (!pubkey) return 0; - hasher_Update(&hasher, pubkey, 33); + const HDNode *pubnode = cryptoMultisigPubkey(coin, multisig, i); + if (!pubnode) return 0; + hasher_Update(&hasher, pubnode->public_key, 33); } d[0] = 0x50 + n; d[1] = 0xAE;