mirror of
https://git.wownero.com/wownero/wownero.git
synced 2024-08-15 01:03:23 +00:00
185 lines
9.3 KiB
C++
185 lines
9.3 KiB
C++
|
// 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
|