add an option to force-update multisig key exchange under some circumstances

This commit is contained in:
koe 2022-05-14 17:07:47 -05:00
parent 7cbae6ca98
commit 1cd21bfba5
15 changed files with 244 additions and 115 deletions

View file

@ -95,9 +95,47 @@ static std::vector<std::string> exchange_round(std::vector<tools::wallet2>& wall
std::vector<std::string> new_infos;
new_infos.reserve(infos.size());
for (size_t i = 0; i < wallets.size(); ++i)
new_infos.push_back(wallets[i].exchange_multisig_keys("", infos));
return new_infos;
}
static std::vector<std::string> exchange_round_force_update(std::vector<tools::wallet2>& wallets,
const std::vector<std::string>& infos,
const std::size_t round_in_progress)
{
EXPECT_TRUE(wallets.size() == infos.size());
std::vector<std::string> new_infos;
std::vector<std::string> temp_force_update_infos;
new_infos.reserve(infos.size());
// when force-updating, we only need at most 'num_signers - 1 - (round - 1)' messages from other signers
size_t num_other_messages_required{wallets.size() - 1 - (round_in_progress - 1)};
if (num_other_messages_required > wallets.size())
num_other_messages_required = 0; //overflow case for post-kex verification round of 1-of-N
for (size_t i = 0; i < wallets.size(); ++i)
{
new_infos.push_back(wallets[i].exchange_multisig_keys("", infos));
temp_force_update_infos.clear();
temp_force_update_infos.reserve(num_other_messages_required + 1);
temp_force_update_infos.push_back(infos[i]); //always include the local signer's message for this round
size_t infos_collected{0};
for (size_t wallet_index = 0; wallet_index < wallets.size(); ++wallet_index)
{
// skip the local signer's message
if (wallet_index == i)
continue;
temp_force_update_infos.push_back(infos[wallet_index]);
++infos_collected;
if (infos_collected == num_other_messages_required)
break;
}
new_infos.push_back(wallets[i].exchange_multisig_keys("", temp_force_update_infos, true));
}
return new_infos;
@ -105,7 +143,7 @@ static std::vector<std::string> exchange_round(std::vector<tools::wallet2>& wall
static void check_results(const std::vector<std::string> &intermediate_infos,
std::vector<tools::wallet2>& wallets,
std::uint32_t M)
const std::uint32_t M)
{
// check results
std::unordered_set<crypto::secret_key> unique_privkeys;
@ -167,8 +205,9 @@ static void check_results(const std::vector<std::string> &intermediate_infos,
wallets[0].encrypt_keys("");
}
static void make_wallets(std::vector<tools::wallet2>& wallets, unsigned int M)
static void make_wallets(const unsigned int M, const unsigned int N, const bool force_update)
{
std::vector<tools::wallet2> wallets(N);
ASSERT_TRUE(wallets.size() > 1 && wallets.size() <= KEYS_COUNT);
ASSERT_TRUE(M <= wallets.size());
std::uint32_t total_rounds_required = multisig::multisig_setup_rounds_required(wallets.size(), M);
@ -207,9 +246,12 @@ static void make_wallets(std::vector<tools::wallet2>& wallets, unsigned int M)
wallets[0].multisig(&ready);
while (!ready)
{
intermediate_infos = exchange_round(wallets, intermediate_infos);
wallets[0].multisig(&ready);
if (force_update)
intermediate_infos = exchange_round_force_update(wallets, intermediate_infos, rounds_complete + 1);
else
intermediate_infos = exchange_round(wallets, intermediate_infos);
wallets[0].multisig(&ready);
++rounds_complete;
}
@ -220,38 +262,38 @@ static void make_wallets(std::vector<tools::wallet2>& wallets, unsigned int M)
TEST(multisig, make_1_2)
{
std::vector<tools::wallet2> wallets(2);
make_wallets(wallets, 1);
make_wallets(1, 2, false);
make_wallets(1, 2, true);
}
TEST(multisig, make_1_3)
{
std::vector<tools::wallet2> wallets(3);
make_wallets(wallets, 1);
make_wallets(1, 3, false);
make_wallets(1, 3, true);
}
TEST(multisig, make_2_2)
{
std::vector<tools::wallet2> wallets(2);
make_wallets(wallets, 2);
make_wallets(2, 2, false);
make_wallets(2, 2, true);
}
TEST(multisig, make_3_3)
{
std::vector<tools::wallet2> wallets(3);
make_wallets(wallets, 3);
make_wallets(3, 3, false);
make_wallets(3, 3, true);
}
TEST(multisig, make_2_3)
{
std::vector<tools::wallet2> wallets(3);
make_wallets(wallets, 2);
make_wallets(2, 3, false);
make_wallets(2, 3, true);
}
TEST(multisig, make_2_4)
{
std::vector<tools::wallet2> wallets(4);
make_wallets(wallets, 2);
make_wallets(2, 4, false);
make_wallets(2, 4, true);
}
TEST(multisig, multisig_kex_msg)
@ -272,9 +314,7 @@ TEST(multisig, multisig_kex_msg)
signing_skey = rct::rct2sk(rct::skGen());
}
crypto::secret_key ancillary_skey = rct::rct2sk(rct::skGen());
while (ancillary_skey == crypto::null_skey)
ancillary_skey = rct::rct2sk(rct::skGen());
const crypto::secret_key ancillary_skey{rct::rct2sk(rct::skGen())};
// misc. edge cases
EXPECT_NO_THROW((multisig_kex_msg{}));
@ -312,8 +352,8 @@ TEST(multisig, multisig_kex_msg)
// test that keys can be recovered if stored in a message and the message's reverse
// round 1
multisig_kex_msg msg_rnd1{1, signing_skey, std::vector<crypto::public_key>{pubkey1}, ancillary_skey};
multisig_kex_msg msg_rnd1_reverse{msg_rnd1.get_msg()};
const multisig_kex_msg msg_rnd1{1, signing_skey, std::vector<crypto::public_key>{pubkey1}, ancillary_skey};
const multisig_kex_msg msg_rnd1_reverse{msg_rnd1.get_msg()};
EXPECT_EQ(msg_rnd1.get_round(), 1);
EXPECT_EQ(msg_rnd1.get_round(), msg_rnd1_reverse.get_round());
EXPECT_EQ(msg_rnd1.get_signing_pubkey(), signing_pubkey);
@ -324,8 +364,8 @@ TEST(multisig, multisig_kex_msg)
EXPECT_EQ(msg_rnd1.get_msg_privkey(), msg_rnd1_reverse.get_msg_privkey());
// round 2
multisig_kex_msg msg_rnd2{2, signing_skey, std::vector<crypto::public_key>{pubkey1, pubkey2}, ancillary_skey};
multisig_kex_msg msg_rnd2_reverse{msg_rnd2.get_msg()};
const multisig_kex_msg msg_rnd2{2, signing_skey, std::vector<crypto::public_key>{pubkey1, pubkey2}, ancillary_skey};
const multisig_kex_msg msg_rnd2_reverse{msg_rnd2.get_msg()};
EXPECT_EQ(msg_rnd2.get_round(), 2);
EXPECT_EQ(msg_rnd2.get_round(), msg_rnd2_reverse.get_round());
EXPECT_EQ(msg_rnd2.get_signing_pubkey(), signing_pubkey);