Skip to content

Commit 7cbae6c

Browse files
committed
Merge pull request #8545
12e7c41 Merge pull request #5 from j-berman/restore-msig-encrypted-seed (Justin Berman) 848a0c0 Fix segfault restoring encrypted multisig seed (j-berman) 401f5d9 Require user ack multisig is experimental to restore (j-berman) fc8a5d6 multisig: fix #8537 seed restore (suggestions by @UkoeHB) (j-berman)
2 parents 0be63cf + 12e7c41 commit 7cbae6c

File tree

8 files changed

+56
-28
lines changed

8 files changed

+56
-28
lines changed

src/multisig/multisig_account.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ namespace multisig
127127
bool multisig_account::multisig_is_ready() const
128128
{
129129
if (main_kex_rounds_done())
130-
return m_kex_rounds_complete >= multisig_kex_rounds_required(m_signers.size(), m_threshold) + 1;
130+
return m_kex_rounds_complete >= multisig_setup_rounds_required(m_signers.size(), m_threshold);
131131
else
132132
return false;
133133
}
@@ -200,4 +200,11 @@ namespace multisig
200200
return num_signers - threshold + 1;
201201
}
202202
//----------------------------------------------------------------------------------------------------------------------
203+
// EXTERNAL
204+
//----------------------------------------------------------------------------------------------------------------------
205+
std::uint32_t multisig_setup_rounds_required(const std::uint32_t num_signers, const std::uint32_t threshold)
206+
{
207+
return multisig_kex_rounds_required(num_signers, threshold) + 1;
208+
}
209+
//----------------------------------------------------------------------------------------------------------------------
203210
} //namespace multisig

src/multisig/multisig_account.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,4 +245,13 @@ namespace multisig
245245
* return: number of kex rounds required
246246
*/
247247
std::uint32_t multisig_kex_rounds_required(const std::uint32_t num_signers, const std::uint32_t threshold);
248+
249+
/**
250+
* brief: multisig_setup_rounds_required - The number of setup rounds required to produce an M-of-N shared key.
251+
* - A participant must complete all kex rounds and 1 initialization round.
252+
* param: num_signers - number of participants in multisig (N)
253+
* param: threshold - threshold of multisig (M)
254+
* return: number of setup rounds required
255+
*/
256+
std::uint32_t multisig_setup_rounds_required(const std::uint32_t num_signers, const std::uint32_t threshold);
248257
} //namespace multisig

src/multisig/multisig_account_kex_impl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ namespace multisig
7474
"Multisig threshold may not be larger than number of signers.");
7575
CHECK_AND_ASSERT_THROW_MES(threshold > 0, "Multisig threshold must be > 0.");
7676
CHECK_AND_ASSERT_THROW_MES(round > 0, "Multisig kex round must be > 0.");
77-
CHECK_AND_ASSERT_THROW_MES(round <= multisig_kex_rounds_required(num_signers, threshold) + 1,
77+
CHECK_AND_ASSERT_THROW_MES(round <= multisig_setup_rounds_required(num_signers, threshold),
7878
"Trying to process multisig kex for an invalid round.");
7979
}
8080
//----------------------------------------------------------------------------------------------------------------------

src/simplewallet/simplewallet.cpp

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4116,6 +4116,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
41164116

41174117
epee::wipeable_string multisig_keys;
41184118
epee::wipeable_string password;
4119+
epee::wipeable_string seed_pass;
41194120

41204121
if (!handle_command_line(vm))
41214122
return false;
@@ -4132,6 +4133,17 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
41324133
if(!ask_wallet_create_if_needed()) return false;
41334134
}
41344135

4136+
bool enable_multisig = false;
4137+
if (m_restore_multisig_wallet) {
4138+
fail_msg_writer() << tr("Multisig is disabled.");
4139+
fail_msg_writer() << tr("Multisig is an experimental feature and may have bugs. Things that could go wrong include: funds sent to a multisig wallet can't be spent at all, can only be spent with the participation of a malicious group member, or can be stolen by a malicious group member.");
4140+
if (!command_line::is_yes(input_line("Do you want to continue restoring a multisig wallet?", true))) {
4141+
message_writer() << tr("You have canceled restoring a multisig wallet.");
4142+
return false;
4143+
}
4144+
enable_multisig = true;
4145+
}
4146+
41354147
if (!m_generate_new.empty() || m_restoring)
41364148
{
41374149
if (!m_subaddress_lookahead.empty() && !parse_subaddress_lookahead(m_subaddress_lookahead))
@@ -4211,19 +4223,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
42114223
auto pwd_container = password_prompter(tr("Enter seed offset passphrase, empty if none"), false);
42124224
if (std::cin.eof() || !pwd_container)
42134225
return false;
4214-
epee::wipeable_string seed_pass = pwd_container->password();
4215-
if (!seed_pass.empty())
4216-
{
4217-
if (m_restore_multisig_wallet)
4218-
{
4219-
crypto::secret_key key;
4220-
crypto::cn_slow_hash(seed_pass.data(), seed_pass.size(), (crypto::hash&)key);
4221-
sc_reduce32((unsigned char*)key.data);
4222-
multisig_keys = m_wallet->decrypt<epee::wipeable_string>(std::string(multisig_keys.data(), multisig_keys.size()), key, true);
4223-
}
4224-
else
4225-
m_recovery_key = cryptonote::decrypt_key(m_recovery_key, seed_pass);
4226-
}
4226+
seed_pass = pwd_container->password();
4227+
if (!seed_pass.empty() && !m_restore_multisig_wallet)
4228+
m_recovery_key = cryptonote::decrypt_key(m_recovery_key, seed_pass);
42274229
}
42284230
if (!m_generate_from_view_key.empty())
42294231
{
@@ -4566,7 +4568,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
45664568
m_wallet_file = m_generate_new;
45674569
boost::optional<epee::wipeable_string> r;
45684570
if (m_restore_multisig_wallet)
4569-
r = new_wallet(vm, multisig_keys, old_language);
4571+
r = new_wallet(vm, multisig_keys, seed_pass, old_language);
45704572
else
45714573
r = new_wallet(vm, m_recovery_key, m_restore_deterministic_wallet, m_non_deterministic, old_language);
45724574
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
@@ -4665,6 +4667,8 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
46654667
}
46664668
m_wallet->set_refresh_from_block_height(m_restore_height);
46674669
}
4670+
if (enable_multisig)
4671+
m_wallet->enable_multisig(true);
46684672
m_wallet->rewrite(m_wallet_file, password);
46694673
}
46704674
else
@@ -5062,7 +5066,7 @@ boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::pr
50625066
}
50635067
//----------------------------------------------------------------------------------------------------
50645068
boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
5065-
const epee::wipeable_string &multisig_keys, const std::string &old_language)
5069+
const epee::wipeable_string &multisig_keys, const epee::wipeable_string &seed_pass, const std::string &old_language)
50665070
{
50675071
std::pair<std::unique_ptr<tools::wallet2>, tools::password_container> rc;
50685072
try { rc = tools::wallet2::make_new(vm, false, password_prompter); }
@@ -5096,7 +5100,16 @@ boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::pr
50965100

50975101
try
50985102
{
5099-
m_wallet->generate(m_wallet_file, std::move(rc.second).password(), multisig_keys, create_address_file);
5103+
if (seed_pass.empty())
5104+
m_wallet->generate(m_wallet_file, std::move(rc.second).password(), multisig_keys, create_address_file);
5105+
else
5106+
{
5107+
crypto::secret_key key;
5108+
crypto::cn_slow_hash(seed_pass.data(), seed_pass.size(), (crypto::hash&)key);
5109+
sc_reduce32((unsigned char*)key.data);
5110+
const epee::wipeable_string &msig_keys = m_wallet->decrypt<epee::wipeable_string>(std::string(multisig_keys.data(), multisig_keys.size()), key, true);
5111+
m_wallet->generate(m_wallet_file, std::move(rc.second).password(), msig_keys, create_address_file);
5112+
}
51005113
bool ready;
51015114
uint32_t threshold, total;
51025115
if (!m_wallet->multisig(&ready, &threshold, &total) || !ready)

src/simplewallet/simplewallet.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ namespace cryptonote
101101
boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm, const cryptonote::account_public_address& address,
102102
const boost::optional<crypto::secret_key>& spendkey, const crypto::secret_key& viewkey);
103103
boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm,
104-
const epee::wipeable_string &multisig_keys, const std::string &old_language);
104+
const epee::wipeable_string &multisig_keys, const epee::wipeable_string &seed_pass, const std::string &old_language);
105105
boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm);
106106
boost::optional<epee::wipeable_string> open_wallet(const boost::program_options::variables_map& vm);
107107
bool close_wallet();

src/wallet/wallet2.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4737,7 +4737,8 @@ void wallet2::init_type(hw::device::device_type device_type)
47374737
}
47384738

47394739
/*!
4740-
* \brief Generates a wallet or restores one.
4740+
* \brief Generates a wallet or restores one. Assumes the multisig setup
4741+
* has already completed for the provided multisig info.
47414742
* \param wallet_ Name of wallet file
47424743
* \param password Password of wallet file
47434744
* \param multisig_data The multisig restore info and keys
@@ -4796,11 +4797,6 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
47964797
crypto::public_key local_signer;
47974798
THROW_WALLET_EXCEPTION_IF(!crypto::secret_key_to_public_key(spend_secret_key, local_signer), error::invalid_multisig_seed);
47984799
THROW_WALLET_EXCEPTION_IF(std::find(multisig_signers.begin(), multisig_signers.end(), local_signer) == multisig_signers.end(), error::invalid_multisig_seed);
4799-
rct::key skey = rct::zero();
4800-
for (const auto &msk: multisig_keys)
4801-
sc_add(skey.bytes, skey.bytes, rct::sk2rct(msk).bytes);
4802-
THROW_WALLET_EXCEPTION_IF(!(rct::rct2sk(skey) == spend_secret_key), error::invalid_multisig_seed);
4803-
memwipe(&skey, sizeof(rct::key));
48044800

48054801
m_account.make_multisig(view_secret_key, spend_secret_key, spend_public_key, multisig_keys);
48064802

@@ -4811,6 +4807,8 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
48114807
m_multisig = true;
48124808
m_multisig_threshold = threshold;
48134809
m_multisig_signers = multisig_signers;
4810+
// wallet is assumed already finalized
4811+
m_multisig_rounds_passed = multisig::multisig_setup_rounds_required(m_multisig_signers.size(), m_multisig_threshold);
48144812
setup_keys(password);
48154813

48164814
create_keys_file(wallet_, false, password, m_nettype != MAINNET || create_address_file);
@@ -5261,7 +5259,7 @@ bool wallet2::multisig(bool *ready, uint32_t *threshold, uint32_t *total) const
52615259
if (ready)
52625260
{
52635261
*ready = !(get_account().get_keys().m_account_address.m_spend_public_key == rct::rct2pk(rct::identity())) &&
5264-
(m_multisig_rounds_passed == multisig::multisig_kex_rounds_required(m_multisig_signers.size(), m_multisig_threshold) + 1);
5262+
(m_multisig_rounds_passed == multisig::multisig_setup_rounds_required(m_multisig_signers.size(), m_multisig_threshold));
52655263
}
52665264
return true;
52675265
}

src/wallet/wallet2.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -817,7 +817,8 @@ namespace tools
817817
};
818818

819819
/*!
820-
* \brief Generates a wallet or restores one.
820+
* \brief Generates a wallet or restores one. Assumes the multisig setup
821+
* has already completed for the provided multisig info.
821822
* \param wallet_ Name of wallet file
822823
* \param password Password of wallet file
823824
* \param multisig_data The multisig restore info and keys

tests/unit_tests/multisig.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ static void make_wallets(std::vector<tools::wallet2>& wallets, unsigned int M)
171171
{
172172
ASSERT_TRUE(wallets.size() > 1 && wallets.size() <= KEYS_COUNT);
173173
ASSERT_TRUE(M <= wallets.size());
174-
std::uint32_t total_rounds_required = multisig::multisig_kex_rounds_required(wallets.size(), M) + 1;
174+
std::uint32_t total_rounds_required = multisig::multisig_setup_rounds_required(wallets.size(), M);
175175
std::uint32_t rounds_complete{0};
176176

177177
// initialize wallets, get first round multisig kex msgs

0 commit comments

Comments
 (0)