aboutsummaryrefslogtreecommitdiff
path: root/src/multisig/multisig_account.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/multisig/multisig_account.cpp')
-rw-r--r--src/multisig/multisig_account.cpp184
1 files changed, 184 insertions, 0 deletions
diff --git a/src/multisig/multisig_account.cpp b/src/multisig/multisig_account.cpp
new file mode 100644
index 000000000..b7298c4b6
--- /dev/null
+++ b/src/multisig/multisig_account.cpp
@@ -0,0 +1,184 @@
+// Copyright (c) 2021, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "multisig_account.h"
+
+#include "crypto/crypto.h"
+#include "cryptonote_config.h"
+#include "include_base_utils.h"
+#include "multisig.h"
+#include "multisig_kex_msg.h"
+#include "ringct/rctOps.h"
+#include "ringct/rctTypes.h"
+
+#include <cstdint>
+#include <utility>
+#include <vector>
+
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "multisig"
+
+namespace multisig
+{
+ //----------------------------------------------------------------------------------------------------------------------
+ // multisig_account: EXTERNAL
+ //----------------------------------------------------------------------------------------------------------------------
+ multisig_account::multisig_account(const crypto::secret_key &base_privkey,
+ const crypto::secret_key &base_common_privkey) :
+ m_base_privkey{base_privkey},
+ m_base_common_privkey{base_common_privkey},
+ m_multisig_pubkey{rct::rct2pk(rct::identity())},
+ m_common_pubkey{rct::rct2pk(rct::identity())},
+ m_kex_rounds_complete{0},
+ m_next_round_kex_message{multisig_kex_msg{1, base_privkey, std::vector<crypto::public_key>{}, base_common_privkey}.get_msg()}
+ {
+ CHECK_AND_ASSERT_THROW_MES(crypto::secret_key_to_public_key(m_base_privkey, m_base_pubkey),
+ "Failed to derive public key");
+ }
+ //----------------------------------------------------------------------------------------------------------------------
+ // multisig_account: EXTERNAL
+ //----------------------------------------------------------------------------------------------------------------------
+ multisig_account::multisig_account(const std::uint32_t threshold,
+ std::vector<crypto::public_key> signers,
+ const crypto::secret_key &base_privkey,
+ const crypto::secret_key &base_common_privkey,
+ std::vector<crypto::secret_key> multisig_privkeys,
+ const crypto::secret_key &common_privkey,
+ const crypto::public_key &multisig_pubkey,
+ const crypto::public_key &common_pubkey,
+ const std::uint32_t kex_rounds_complete,
+ kex_origins_map_t kex_origins_map,
+ std::string next_round_kex_message) :
+ m_base_privkey{base_privkey},
+ m_base_common_privkey{base_common_privkey},
+ m_multisig_privkeys{std::move(multisig_privkeys)},
+ m_common_privkey{common_privkey},
+ m_multisig_pubkey{multisig_pubkey},
+ m_common_pubkey{common_pubkey},
+ m_kex_rounds_complete{kex_rounds_complete},
+ m_kex_keys_to_origins_map{std::move(kex_origins_map)},
+ m_next_round_kex_message{std::move(next_round_kex_message)}
+ {
+ CHECK_AND_ASSERT_THROW_MES(kex_rounds_complete > 0, "multisig account: can't reconstruct account if its kex wasn't initialized");
+ CHECK_AND_ASSERT_THROW_MES(crypto::secret_key_to_public_key(m_base_privkey, m_base_pubkey),
+ "Failed to derive public key");
+ set_multisig_config(threshold, std::move(signers));
+ }
+ //----------------------------------------------------------------------------------------------------------------------
+ // multisig_account: EXTERNAL
+ //----------------------------------------------------------------------------------------------------------------------
+ bool multisig_account::account_is_active() const
+ {
+ return m_kex_rounds_complete > 0;
+ }
+ //----------------------------------------------------------------------------------------------------------------------
+ // multisig_account: EXTERNAL
+ //----------------------------------------------------------------------------------------------------------------------
+ bool multisig_account::multisig_is_ready() const
+ {
+ if (account_is_active())
+ return multisig_kex_rounds_required(m_signers.size(), m_threshold) == m_kex_rounds_complete;
+ else
+ return false;
+ }
+ //----------------------------------------------------------------------------------------------------------------------
+ // multisig_account: INTERNAL
+ //----------------------------------------------------------------------------------------------------------------------
+ void multisig_account::set_multisig_config(const std::size_t threshold, std::vector<crypto::public_key> signers)
+ {
+ // validate
+ CHECK_AND_ASSERT_THROW_MES(threshold > 0 && threshold <= signers.size(), "multisig account: tried to set invalid threshold.");
+ CHECK_AND_ASSERT_THROW_MES(signers.size() >= 2 && signers.size() <= config::MULTISIG_MAX_SIGNERS,
+ "multisig account: tried to set invalid number of signers.");
+
+ for (auto signer_it = signers.begin(); signer_it != signers.end(); ++signer_it)
+ {
+ // signers should all be unique
+ CHECK_AND_ASSERT_THROW_MES(std::find(signers.begin(), signer_it, *signer_it) == signer_it,
+ "multisig account: tried to set signers, but found a duplicate signer unexpectedly.");
+
+ // signer pubkeys must be in main subgroup, and not identity
+ CHECK_AND_ASSERT_THROW_MES(rct::isInMainSubgroup(rct::pk2rct(*signer_it)) && !(*signer_it == rct::rct2pk(rct::identity())),
+ "multisig account: tried to set signers, but a signer pubkey is invalid.");
+ }
+
+ // own pubkey should be in signers list
+ CHECK_AND_ASSERT_THROW_MES(std::find(signers.begin(), signers.end(), m_base_pubkey) != signers.end(),
+ "multisig account: tried to set signers, but did not find the account's base pubkey in signer list.");
+
+ // sort signers
+ std::sort(signers.begin(), signers.end(),
+ [](const crypto::public_key &key1, const crypto::public_key &key2) -> bool
+ {
+ return memcmp(&key1, &key2, sizeof(crypto::public_key)) < 0;
+ }
+ );
+
+ // set
+ m_threshold = threshold;
+ m_signers = std::move(signers);
+ }
+ //----------------------------------------------------------------------------------------------------------------------
+ // multisig_account: EXTERNAL
+ //----------------------------------------------------------------------------------------------------------------------
+ void multisig_account::initialize_kex(const std::uint32_t threshold,
+ std::vector<crypto::public_key> signers,
+ const std::vector<multisig_kex_msg> &expanded_msgs_rnd1)
+ {
+ CHECK_AND_ASSERT_THROW_MES(!account_is_active(), "multisig account: tried to initialize kex, but already initialized");
+
+ // only mutate account if update succeeds
+ multisig_account temp_account{*this};
+ temp_account.set_multisig_config(threshold, std::move(signers));
+ temp_account.kex_update_impl(expanded_msgs_rnd1);
+ *this = std::move(temp_account);
+ }
+ //----------------------------------------------------------------------------------------------------------------------
+ // multisig_account: EXTERNAL
+ //----------------------------------------------------------------------------------------------------------------------
+ void multisig_account::kex_update(const std::vector<multisig_kex_msg> &expanded_msgs)
+ {
+ CHECK_AND_ASSERT_THROW_MES(account_is_active(), "multisig account: tried to update kex, but kex isn't initialized yet.");
+ CHECK_AND_ASSERT_THROW_MES(!multisig_is_ready(), "multisig account: tried to update kex, but kex is already complete.");
+
+ multisig_account temp_account{*this};
+ temp_account.kex_update_impl(expanded_msgs);
+ *this = std::move(temp_account);
+ }
+ //----------------------------------------------------------------------------------------------------------------------
+ // EXTERNAL
+ //----------------------------------------------------------------------------------------------------------------------
+ std::uint32_t multisig_kex_rounds_required(const std::uint32_t num_signers, const std::uint32_t threshold)
+ {
+ CHECK_AND_ASSERT_THROW_MES(num_signers >= threshold, "num_signers must be >= threshold");
+ CHECK_AND_ASSERT_THROW_MES(threshold >= 1, "threshold must be >= 1");
+ return num_signers - threshold + 1;
+ }
+ //----------------------------------------------------------------------------------------------------------------------
+} //namespace multisig