diff options
Diffstat (limited to 'src/wallet/wallet2.cpp')
-rw-r--r-- | src/wallet/wallet2.cpp | 61 |
1 files changed, 33 insertions, 28 deletions
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 446962d6b..6323c793c 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -986,6 +986,21 @@ bool get_pruned_tx(const cryptonote::COMMAND_RPC_GET_TRANSACTIONS::entry &entry, return false; } +// Given M (threshold) and N (total), calculate the number of private multisig keys each +// signer should have. This value is equal to (N - 1) choose (N - M) +// Prereq: M >= 1 && N >= M && N <= 16 +uint64_t num_priv_multisig_keys_post_setup(uint64_t threshold, uint64_t total) +{ + THROW_WALLET_EXCEPTION_IF(threshold < 1 || total < threshold || threshold > 16, + tools::error::wallet_internal_error, "Invalid arguments to num_priv_multisig_keys_post_setup"); + + uint64_t n_multisig_keys = 1; + for (uint64_t i = 2; i <= total - 1; ++i) n_multisig_keys *= i; // multiply by (N - 1)! + for (uint64_t i = 2; i <= total - threshold; ++i) n_multisig_keys /= i; // divide by (N - M)! + for (uint64_t i = 2; i <= threshold - 1; ++i) n_multisig_keys /= i; // divide by ((N - 1) - (N - M))! + return n_multisig_keys; +} + //----------------------------------------------------------------- } //namespace @@ -1394,7 +1409,7 @@ bool wallet2::get_seed(epee::wipeable_string& electrum_words, const epee::wipeab return true; } //---------------------------------------------------------------------------------------------------- -bool wallet2::get_multisig_seed(epee::wipeable_string& seed, const epee::wipeable_string &passphrase, bool raw) const +bool wallet2::get_multisig_seed(epee::wipeable_string& seed, const epee::wipeable_string &passphrase) const { bool ready; uint32_t threshold, total; @@ -1408,15 +1423,14 @@ bool wallet2::get_multisig_seed(epee::wipeable_string& seed, const epee::wipeabl std::cout << "This multisig wallet is not yet finalized" << std::endl; return false; } - if (!raw && seed_language.empty()) - { - std::cout << "seed_language not set" << std::endl; - return false; - } + + const uint64_t num_expected_ms_keys = num_priv_multisig_keys_post_setup(threshold, total); crypto::secret_key skey; crypto::public_key pkey; const account_keys &keys = get_account().get_keys(); + THROW_WALLET_EXCEPTION_IF(num_expected_ms_keys != keys.m_multisig_keys.size(), + error::wallet_internal_error, "Unexpected number of private multisig keys") epee::wipeable_string data; data.append((const char*)&threshold, sizeof(uint32_t)); data.append((const char*)&total, sizeof(uint32_t)); @@ -1441,18 +1455,7 @@ bool wallet2::get_multisig_seed(epee::wipeable_string& seed, const epee::wipeabl data = encrypt(data, key, true); } - if (raw) - { - seed = epee::to_hex::wipeable_string({(const unsigned char*)data.data(), data.size()}); - } - else - { - if (!crypto::ElectrumWords::bytes_to_words(data.data(), data.size(), seed, seed_language)) - { - std::cout << "Failed to encode seed"; - return false; - } - } + seed = epee::to_hex::wipeable_string({(const unsigned char*)data.data(), data.size()}); return true; } @@ -1988,14 +1991,14 @@ bool wallet2::frozen(const multisig_tx_set& txs) const CHECK_AND_ASSERT_THROW_MES(cd.sources.size() == ptx.tx.vin.size(), "mismatched multisg tx set source sizes"); for (size_t src_idx = 0; src_idx < cd.sources.size(); ++src_idx) { - // Check that the key images are consistent between tx vin and construction data + // Extract keys images from tx vin and construction data const crypto::key_image multisig_ki = rct::rct2ki(cd.sources[src_idx].multisig_kLRki.ki); CHECK_AND_ASSERT_THROW_MES(ptx.tx.vin[src_idx].type() == typeid(cryptonote::txin_to_key), "multisig tx cannot be miner"); - const crypto::key_image vin_ki = boost::get<cryptonote::txin_to_key>(ptx.tx.vin[src_idx]).k_image; - CHECK_AND_ASSERT_THROW_MES(multisig_ki == vin_ki, "Mismatched key image b/t vin and construction data"); + const crypto::key_image& vin_ki = boost::get<cryptonote::txin_to_key>(ptx.tx.vin[src_idx]).k_image; - // Add key image to set + // Add key images to set (there will be some overlap) kis_to_sign.insert(multisig_ki); + kis_to_sign.insert(vin_ki); } } // Step 2. Scan all transfers for frozen key images @@ -5217,9 +5220,11 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& offset += sizeof(uint32_t); uint32_t total = *(uint32_t*)(multisig_data.data() + offset); offset += sizeof(uint32_t); - THROW_WALLET_EXCEPTION_IF(threshold < 2, error::invalid_multisig_seed); - THROW_WALLET_EXCEPTION_IF(total != threshold && total != threshold + 1, error::invalid_multisig_seed); - const size_t n_multisig_keys = total == threshold ? 1 : threshold; + + THROW_WALLET_EXCEPTION_IF(threshold < 1, error::invalid_multisig_seed); + THROW_WALLET_EXCEPTION_IF(total < threshold, error::invalid_multisig_seed); + THROW_WALLET_EXCEPTION_IF(threshold > 16, error::invalid_multisig_seed); // doing N choose (N - M + 1) might overflow + const uint64_t n_multisig_keys = num_priv_multisig_keys_post_setup(threshold, total); THROW_WALLET_EXCEPTION_IF(multisig_data.size() != 8 + 32 * (4 + n_multisig_keys + total), error::invalid_multisig_seed); std::vector<crypto::secret_key> multisig_keys; @@ -10222,7 +10227,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp else { LOG_PRINT_L2("We made a tx, adjusting fee and saving it, we need " << print_money(needed_fee) << " and we have " << print_money(test_ptx.fee)); - while (needed_fee > test_ptx.fee) { + do { if (use_rct) transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, test_tx, test_ptx, rct_config, use_view_tags); @@ -10233,7 +10238,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_quantization_mask); LOG_PRINT_L2("Made an attempt at a final " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_money(test_ptx.fee) << " fee and " << print_money(test_ptx.change_dts.amount) << " change"); - } + } while (needed_fee > test_ptx.fee); LOG_PRINT_L2("Made a final " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_money(test_ptx.fee) << " fee and " << print_money(test_ptx.change_dts.amount) << " change"); @@ -10629,7 +10634,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton THROW_WALLET_EXCEPTION_IF(needed_fee > available_for_fee, error::wallet_internal_error, "Transaction cannot pay for itself"); do { - LOG_PRINT_L2("We made a tx, adjusting fee and saving it"); + LOG_PRINT_L2("We made a tx, adjusting fee and saving it, we need " << print_money(needed_fee) << " and we have " << print_money(test_ptx.fee)); // distribute total transferred amount between outputs uint64_t amount_transferred = available_for_fee - needed_fee; uint64_t dt_amount = amount_transferred / outputs; |