aboutsummaryrefslogtreecommitdiff
path: root/tests/unit_tests/multisig.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit_tests/multisig.cpp')
-rw-r--r--tests/unit_tests/multisig.cpp161
1 files changed, 141 insertions, 20 deletions
diff --git a/tests/unit_tests/multisig.cpp b/tests/unit_tests/multisig.cpp
index c044591c1..1b3a455c0 100644
--- a/tests/unit_tests/multisig.cpp
+++ b/tests/unit_tests/multisig.cpp
@@ -149,6 +149,7 @@ static void check_results(const std::vector<std::string> &intermediate_infos,
std::unordered_set<crypto::secret_key> unique_privkeys;
rct::key composite_pubkey = rct::identity();
+ ASSERT_TRUE(wallets.size() > 0);
wallets[0].decrypt_keys("");
crypto::public_key spend_pubkey = wallets[0].get_account().get_keys().m_account_address.m_spend_public_key;
crypto::secret_key view_privkey = wallets[0].get_account().get_keys().m_view_secret_key;
@@ -156,32 +157,48 @@ static void check_results(const std::vector<std::string> &intermediate_infos,
EXPECT_TRUE(crypto::secret_key_to_public_key(view_privkey, view_pubkey));
wallets[0].encrypt_keys("");
- for (size_t i = 0; i < wallets.size(); ++i)
+ // at the end of multisig kex, all wallets should emit a post-kex message with the same two pubkeys
+ std::vector<crypto::public_key> post_kex_msg_pubkeys;
+ ASSERT_TRUE(intermediate_infos.size() == wallets.size());
+ for (const std::string &intermediate_info : intermediate_infos)
+ {
+ multisig::multisig_kex_msg post_kex_msg;
+ EXPECT_TRUE(!intermediate_info.empty());
+ EXPECT_NO_THROW(post_kex_msg = intermediate_info);
+
+ if (post_kex_msg_pubkeys.size() != 0)
+ EXPECT_TRUE(post_kex_msg_pubkeys == post_kex_msg.get_msg_pubkeys()); //assumes sorting is always the same
+ else
+ post_kex_msg_pubkeys = post_kex_msg.get_msg_pubkeys();
+
+ EXPECT_TRUE(post_kex_msg_pubkeys.size() == 2);
+ }
+
+ // the post-kex pubkeys should equal the account's public view and spend keys
+ EXPECT_TRUE(std::find(post_kex_msg_pubkeys.begin(), post_kex_msg_pubkeys.end(), spend_pubkey) != post_kex_msg_pubkeys.end());
+ EXPECT_TRUE(std::find(post_kex_msg_pubkeys.begin(), post_kex_msg_pubkeys.end(), view_pubkey) != post_kex_msg_pubkeys.end());
+
+ // each wallet should have the same state (private view key, public spend key), and the public spend key should be
+ // reproducible from the private spend keys found in each account
+ for (tools::wallet2 &wallet : wallets)
{
- EXPECT_TRUE(!intermediate_infos[i].empty());
- const multisig::multisig_account_status ms_status{wallets[i].get_multisig_status()};
+ wallet.decrypt_keys("");
+ const multisig::multisig_account_status ms_status{wallet.get_multisig_status()};
EXPECT_TRUE(ms_status.multisig_is_active);
EXPECT_TRUE(ms_status.kex_is_done);
EXPECT_TRUE(ms_status.is_ready);
EXPECT_TRUE(ms_status.threshold == M);
EXPECT_TRUE(ms_status.total == wallets.size());
- wallets[i].decrypt_keys("");
-
- if (i != 0)
- {
- // "equals" is transitive relation so we need only to compare first wallet's address to each others' addresses.
- // no need to compare 0's address with itself.
- EXPECT_TRUE(wallets[0].get_account().get_public_address_str(cryptonote::TESTNET) ==
- wallets[i].get_account().get_public_address_str(cryptonote::TESTNET));
-
- EXPECT_EQ(spend_pubkey, wallets[i].get_account().get_keys().m_account_address.m_spend_public_key);
- EXPECT_EQ(view_privkey, wallets[i].get_account().get_keys().m_view_secret_key);
- EXPECT_EQ(view_pubkey, wallets[i].get_account().get_keys().m_account_address.m_view_public_key);
- }
+ EXPECT_TRUE(wallets[0].get_account().get_public_address_str(cryptonote::TESTNET) ==
+ wallet.get_account().get_public_address_str(cryptonote::TESTNET));
+
+ EXPECT_EQ(spend_pubkey, wallet.get_account().get_keys().m_account_address.m_spend_public_key);
+ EXPECT_EQ(view_privkey, wallet.get_account().get_keys().m_view_secret_key);
+ EXPECT_EQ(view_pubkey, wallet.get_account().get_keys().m_account_address.m_view_public_key);
// sum together unique multisig keys
- for (const auto &privkey : wallets[i].get_account().get_keys().m_multisig_keys)
+ for (const auto &privkey : wallet.get_account().get_keys().m_multisig_keys)
{
EXPECT_NE(privkey, crypto::null_skey);
@@ -189,17 +206,17 @@ static void check_results(const std::vector<std::string> &intermediate_infos,
{
unique_privkeys.insert(privkey);
crypto::public_key pubkey;
- crypto::secret_key_to_public_key(privkey, pubkey);
+ EXPECT_TRUE(crypto::secret_key_to_public_key(privkey, pubkey));
EXPECT_NE(privkey, crypto::null_skey);
EXPECT_NE(pubkey, crypto::null_pkey);
EXPECT_NE(pubkey, rct::rct2pk(rct::identity()));
rct::addKeys(composite_pubkey, composite_pubkey, rct::pk2rct(pubkey));
}
}
- wallets[i].encrypt_keys("");
+ wallet.encrypt_keys("");
}
- // final key via sums should equal the wallets' public spend key
+ // final key via sum of privkeys should equal the wallets' public spend key
wallets[0].decrypt_keys("");
EXPECT_EQ(wallets[0].get_account().get_keys().m_account_address.m_spend_public_key, rct::rct2pk(composite_pubkey));
wallets[0].encrypt_keys("");
@@ -257,6 +274,104 @@ static void make_wallets(const unsigned int M, const unsigned int N, const bool
check_results(intermediate_infos, wallets, M);
}
+static void make_wallets_boosting(std::vector<tools::wallet2>& wallets, unsigned int M)
+{
+ ASSERT_TRUE(wallets.size() > 1 && wallets.size() <= KEYS_COUNT);
+ ASSERT_TRUE(M <= wallets.size());
+ std::uint32_t kex_rounds_required = multisig::multisig_kex_rounds_required(wallets.size(), M);
+ std::uint32_t rounds_required = multisig::multisig_setup_rounds_required(wallets.size(), M);
+ std::uint32_t rounds_complete{0};
+
+ // initialize wallets, get first round multisig kex msgs
+ std::vector<std::string> initial_infos(wallets.size());
+
+ for (size_t i = 0; i < wallets.size(); ++i)
+ {
+ make_wallet(i, wallets[i]);
+
+ wallets[i].decrypt_keys("");
+ initial_infos[i] = wallets[i].get_multisig_first_kex_msg();
+ wallets[i].encrypt_keys("");
+ }
+
+ // wallets should not be multisig yet
+ for (const auto &wallet: wallets)
+ {
+ const multisig::multisig_account_status ms_status{wallet.get_multisig_status()};
+ ASSERT_FALSE(ms_status.multisig_is_active);
+ }
+
+ // get round 2 booster messages for wallet0 (if appropriate)
+ auto initial_infos_truncated = initial_infos;
+ initial_infos_truncated.erase(initial_infos_truncated.begin());
+
+ std::vector<std::string> wallet0_booster_infos;
+ wallet0_booster_infos.reserve(wallets.size() - 1);
+
+ if (rounds_complete + 1 < kex_rounds_required)
+ {
+ for (size_t i = 1; i < wallets.size(); ++i)
+ {
+ wallet0_booster_infos.push_back(
+ wallets[i].get_multisig_key_exchange_booster("", initial_infos_truncated, M, wallets.size())
+ );
+ }
+ }
+
+ // make wallets multisig
+ std::vector<std::string> intermediate_infos(wallets.size());
+
+ for (size_t i = 0; i < wallets.size(); ++i)
+ intermediate_infos[i] = wallets[i].make_multisig("", initial_infos, M);
+
+ ++rounds_complete;
+
+ // perform all kex rounds
+ // boost wallet0 each round, so wallet0 is always 1 round ahead
+ std::string wallet0_intermediate_info;
+ std::vector<std::string> new_infos(intermediate_infos.size());
+ multisig::multisig_account_status ms_status{wallets[0].get_multisig_status()};
+ while (!ms_status.is_ready)
+ {
+ // use booster infos to update wallet0 'early'
+ if (rounds_complete < kex_rounds_required)
+ new_infos[0] = wallets[0].exchange_multisig_keys("", wallet0_booster_infos);
+ else
+ {
+ // force update the post-kex round with wallet0's post-kex message since wallet0 is 'ahead' of the other wallets
+ wallet0_booster_infos = {wallets[0].exchange_multisig_keys("", {})};
+ new_infos[0] = wallets[0].exchange_multisig_keys("", wallet0_booster_infos, true);
+ }
+
+ // get wallet0 booster infos for next round
+ if (rounds_complete + 1 < kex_rounds_required)
+ {
+ // remove wallet0 info for this round (so boosters have incomplete kex message set)
+ auto intermediate_infos_truncated = intermediate_infos;
+ intermediate_infos_truncated.erase(intermediate_infos_truncated.begin());
+
+ // obtain booster messages from all other wallets
+ for (size_t i = 1; i < wallets.size(); ++i)
+ {
+ wallet0_booster_infos[i-1] =
+ wallets[i].get_multisig_key_exchange_booster("", intermediate_infos_truncated, M, wallets.size());
+ }
+ }
+
+ // update other wallets
+ for (size_t i = 1; i < wallets.size(); ++i)
+ new_infos[i] = wallets[i].exchange_multisig_keys("", intermediate_infos);
+
+ intermediate_infos = new_infos;
+ ++rounds_complete;
+ ms_status = wallets[0].get_multisig_status();
+ }
+
+ EXPECT_EQ(rounds_required, rounds_complete);
+
+ check_results(intermediate_infos, wallets, M);
+}
+
TEST(multisig, make_1_2)
{
make_wallets(1, 2, false);
@@ -293,6 +408,12 @@ TEST(multisig, make_2_4)
make_wallets(2, 4, true);
}
+TEST(multisig, make_2_4_boosting)
+{
+ std::vector<tools::wallet2> wallets(4);
+ make_wallets_boosting(wallets, 2);
+}
+
TEST(multisig, multisig_kex_msg)
{
using namespace multisig;