mirror of
https://github.com/monero-project/monero.git
synced 2024-11-17 08:17:37 +00:00
gen_multisig: generates multisig wallets if participants trust each other
This commit is contained in:
parent
95a21a793d
commit
fff871a455
9 changed files with 283 additions and 10 deletions
|
@ -129,6 +129,7 @@ endif()
|
|||
add_subdirectory(cryptonote_protocol)
|
||||
if(NOT IOS)
|
||||
add_subdirectory(simplewallet)
|
||||
add_subdirectory(gen_multisig)
|
||||
add_subdirectory(daemonizer)
|
||||
add_subdirectory(daemon)
|
||||
add_subdirectory(blockchain_utilities)
|
||||
|
|
54
src/gen_multisig/CMakeLists.txt
Normal file
54
src/gen_multisig/CMakeLists.txt
Normal file
|
@ -0,0 +1,54 @@
|
|||
# Copyright (c) 2017, 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.
|
||||
|
||||
set(gen_multisig_sources
|
||||
gen_multisig.cpp)
|
||||
|
||||
monero_add_executable(gen_multisig
|
||||
${gen_multisig_sources})
|
||||
target_link_libraries(gen_multisig
|
||||
PRIVATE
|
||||
wallet
|
||||
cryptonote_core
|
||||
cncrypto
|
||||
common
|
||||
epee
|
||||
${EPEE_READLINE}
|
||||
${Boost_CHRONO_LIBRARY}
|
||||
${Boost_PROGRAM_OPTIONS_LIBRARY}
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
${Boost_THREAD_LIBRARY}
|
||||
${Readline_LIBRARY}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${EXTRA_LIBRARIES})
|
||||
add_dependencies(gen_multisig
|
||||
version)
|
||||
set_property(TARGET gen_multisig
|
||||
PROPERTY
|
||||
OUTPUT_NAME "monero-gen-trusted-multisig")
|
||||
install(TARGETS gen_multisig DESTINATION bin)
|
213
src/gen_multisig/gen_multisig.cpp
Normal file
213
src/gen_multisig/gen_multisig.cpp
Normal file
|
@ -0,0 +1,213 @@
|
|||
// Copyright (c) 2017, 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.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
/*!
|
||||
* \file gen_multisig.cpp
|
||||
*
|
||||
* \brief Generates a set of multisig wallets
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include "include_base_utils.h"
|
||||
#include "crypto/crypto.h" // for crypto::secret_key definition
|
||||
#include "common/i18n.h"
|
||||
#include "common/command_line.h"
|
||||
#include "common/util.h"
|
||||
#include "common/scoped_message_writer.h"
|
||||
#include "wallet/wallet_args.h"
|
||||
#include "wallet/wallet2.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace epee;
|
||||
using namespace cryptonote;
|
||||
using boost::lexical_cast;
|
||||
namespace po = boost::program_options;
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "wallet.gen_multisig"
|
||||
|
||||
namespace genms
|
||||
{
|
||||
const char* tr(const char* str)
|
||||
{
|
||||
return i18n_translate(str, "tools::gen_multisig");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
const command_line::arg_descriptor<std::string> arg_filename_base = {"filename-base", genms::tr("Base filename (-1, -2, etc suffixes will be appended as needed)"), ""};
|
||||
const command_line::arg_descriptor<std::string> arg_scheme = {"scheme", genms::tr("Give threshold and participants at once as M/N"), ""};
|
||||
const command_line::arg_descriptor<uint32_t> arg_participants = {"participants", genms::tr("How many participants wil share parts of the multisig wallet"), 0};
|
||||
const command_line::arg_descriptor<uint32_t> arg_threshold = {"threshold", genms::tr("How many signers are required to sign a valid transaction"), 0};
|
||||
const command_line::arg_descriptor<bool, false> arg_testnet = {"testnet", genms::tr("Create testnet multisig wallets"), false};
|
||||
|
||||
const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""};
|
||||
}
|
||||
|
||||
static bool generate_multisig(uint32_t threshold, uint32_t total, const std::string &basename, bool testnet)
|
||||
{
|
||||
tools::msg_writer() << (boost::format(genms::tr("Generating %u %u/%u multisig wallets")) % total % threshold % total).str();
|
||||
|
||||
const auto pwd_container = tools::password_container::prompt(true, "Enter password for new multisig wallets");
|
||||
|
||||
try
|
||||
{
|
||||
// create M wallets first
|
||||
std::vector<boost::shared_ptr<tools::wallet2>> wallets(total);
|
||||
for (size_t n = 0; n < total; ++n)
|
||||
{
|
||||
std::string name = basename + "-" + std::to_string(n + 1);
|
||||
wallets[n].reset(new tools::wallet2(testnet));
|
||||
wallets[n]->init("");
|
||||
wallets[n]->generate(name, pwd_container->password(), rct::rct2sk(rct::skGen()), false, false);
|
||||
}
|
||||
|
||||
// gather the keys
|
||||
std::vector<crypto::secret_key> sk(total);
|
||||
std::vector<crypto::public_key> pk(total);
|
||||
for (size_t n = 0; n < total; ++n)
|
||||
{
|
||||
tools::wallet2::verify_multisig_info(wallets[n]->get_multisig_info(), sk[n], pk[n]);
|
||||
}
|
||||
|
||||
// make the wallets multisig
|
||||
std::stringstream ss;
|
||||
for (size_t n = 0; n < total; ++n)
|
||||
{
|
||||
std::string name = basename + "-" + std::to_string(n + 1);
|
||||
std::vector<crypto::secret_key> skn;
|
||||
std::vector<crypto::public_key> pkn;
|
||||
for (size_t k = 0; k < total; ++k)
|
||||
{
|
||||
if (k != n)
|
||||
{
|
||||
skn.push_back(sk[k]);
|
||||
pkn.push_back(pk[k]);
|
||||
}
|
||||
}
|
||||
wallets[n]->make_multisig(pwd_container->password(), skn, pkn, threshold);
|
||||
ss << " " << name << std::endl;
|
||||
}
|
||||
|
||||
std::string address = wallets[0]->get_account().get_public_address_str(wallets[0]->testnet());
|
||||
tools::success_msg_writer() << genms::tr("Generated multisig wallets for address ") << address << std::endl << ss.str();
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
tools::fail_msg_writer() << genms::tr("Error creating multisig wallets: ") << e.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
po::options_description desc_params(wallet_args::tr("Wallet options"));
|
||||
command_line::add_arg(desc_params, arg_filename_base);
|
||||
command_line::add_arg(desc_params, arg_scheme);
|
||||
command_line::add_arg(desc_params, arg_threshold);
|
||||
command_line::add_arg(desc_params, arg_participants);
|
||||
command_line::add_arg(desc_params, arg_testnet);
|
||||
|
||||
const auto vm = wallet_args::main(
|
||||
argc, argv,
|
||||
"monero-gen-multisig [--testnet] [--filename-base=<filename>] [--scheme=M/N] [--threshold=M] [--participants=N]",
|
||||
genms::tr("This program generates a set of multisig wallets - use this simpler scheme only if all the participants trust each other"),
|
||||
desc_params,
|
||||
boost::program_options::positional_options_description(),
|
||||
[](const std::string &s, bool emphasis){ tools::scoped_message_writer(emphasis ? epee::console_color_white : epee::console_color_default, true) << s; },
|
||||
"monero-gen-multisig.log"
|
||||
);
|
||||
if (!vm)
|
||||
return 1;
|
||||
|
||||
bool testnet;
|
||||
uint32_t threshold = 0, total = 0;
|
||||
std::string basename;
|
||||
|
||||
testnet = command_line::get_arg(*vm, arg_testnet);
|
||||
if (command_line::has_arg(*vm, arg_scheme))
|
||||
{
|
||||
if (sscanf(command_line::get_arg(*vm, arg_scheme).c_str(), "%u/%u", &threshold, &total) != 2)
|
||||
{
|
||||
tools::fail_msg_writer() << genms::tr("Error: expected N/M, but got: ") << command_line::get_arg(*vm, arg_scheme);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (!(*vm)["threshold"].defaulted())
|
||||
{
|
||||
if (threshold)
|
||||
{
|
||||
tools::fail_msg_writer() << genms::tr("Error: either --scheme or both of --threshold and --participants may be given");
|
||||
return 1;
|
||||
}
|
||||
threshold = command_line::get_arg(*vm, arg_threshold);
|
||||
}
|
||||
if (!(*vm)["participants"].defaulted())
|
||||
{
|
||||
if (total)
|
||||
{
|
||||
tools::fail_msg_writer() << genms::tr("Error: either --scheme or both of --threshold and --participants may be given");
|
||||
return 1;
|
||||
}
|
||||
total = command_line::get_arg(*vm, arg_participants);
|
||||
}
|
||||
if (threshold <= 1 || threshold > total)
|
||||
{
|
||||
tools::fail_msg_writer() << (boost::format(genms::tr("Error: expected N > 1 and N <= M, but got N==%u and M==%d")) % threshold % total).str();
|
||||
return 1;
|
||||
}
|
||||
if (!(*vm)["filename-base"].defaulted() && !command_line::get_arg(*vm, arg_filename_base).empty())
|
||||
{
|
||||
basename = command_line::get_arg(*vm, arg_filename_base);
|
||||
}
|
||||
else
|
||||
{
|
||||
tools::fail_msg_writer() << genms::tr("Error: --filename-base is required");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (threshold != total-1 && threshold != total)
|
||||
{
|
||||
tools::fail_msg_writer() << genms::tr("Error: unsupported scheme: only N/N and N-1/N are supported");
|
||||
return 1;
|
||||
}
|
||||
if (!generate_multisig(threshold, total, basename, testnet))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
//CATCH_ENTRY_L0("main", 1);
|
||||
}
|
|
@ -6396,6 +6396,7 @@ int main(int argc, char* argv[])
|
|||
const auto vm = wallet_args::main(
|
||||
argc, argv,
|
||||
"monero-wallet-cli [--wallet-file=<file>|--generate-new-wallet=<file>] [<COMMAND>]",
|
||||
sw::tr("This is the command line monero wallet. It needs to connect to a monero\ndaemon to work correctly."),
|
||||
desc_params,
|
||||
positional_options,
|
||||
[](const std::string &s, bool emphasis){ tools::scoped_message_writer(emphasis ? epee::console_color_white : epee::console_color_default, true) << s; },
|
||||
|
|
|
@ -8108,7 +8108,6 @@ size_t wallet2::import_multisig(std::vector<std::vector<tools::wallet2::multisig
|
|||
break;
|
||||
}
|
||||
|
||||
MFATAL("import_multisig: updating from import");
|
||||
for (size_t n = 0; n < n_outputs && n < m_transfers.size(); ++n)
|
||||
{
|
||||
update_multisig_rescan_info(k, info, n);
|
||||
|
@ -8118,7 +8117,6 @@ size_t wallet2::import_multisig(std::vector<std::vector<tools::wallet2::multisig
|
|||
m_multisig_rescan_info = &info;
|
||||
try
|
||||
{
|
||||
MFATAL("import_multisig: refreshing");
|
||||
refresh();
|
||||
}
|
||||
catch (...) {}
|
||||
|
|
|
@ -85,6 +85,7 @@ namespace wallet_args
|
|||
boost::optional<boost::program_options::variables_map> main(
|
||||
int argc, char** argv,
|
||||
const char* const usage,
|
||||
const char* const notice,
|
||||
boost::program_options::options_description desc_params,
|
||||
const boost::program_options::positional_options_description& positional_options,
|
||||
const std::function<void(const std::string&, bool)> &print,
|
||||
|
@ -179,6 +180,9 @@ namespace wallet_args
|
|||
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
|
||||
}
|
||||
|
||||
if (notice)
|
||||
Print(print) << notice << ENDL;
|
||||
|
||||
if (!command_line::is_arg_defaulted(vm, arg_max_concurrency))
|
||||
tools::set_max_concurrency(command_line::get_arg(vm, arg_max_concurrency));
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ namespace wallet_args
|
|||
boost::optional<boost::program_options::variables_map> main(
|
||||
int argc, char** argv,
|
||||
const char* const usage,
|
||||
const char* const notice,
|
||||
boost::program_options::options_description desc_params,
|
||||
const boost::program_options::positional_options_description& positional_options,
|
||||
const std::function<void(const std::string&, bool)> &print,
|
||||
|
|
|
@ -2361,6 +2361,7 @@ int main(int argc, char** argv) {
|
|||
const auto vm = wallet_args::main(
|
||||
argc, argv,
|
||||
"monero-wallet-rpc [--wallet-file=<file>|--generate-from-json=<file>|--wallet-dir=<directory>] [--rpc-bind-port=<port>]",
|
||||
tools::wallet_rpc_server::tr("This is the RPC monero wallet. It needs to connect to a monero\ndaemon to work correctly."),
|
||||
desc_params,
|
||||
po::positional_options_description(),
|
||||
[](const std::string &s, bool emphasis){ epee::set_console_color(emphasis ? epee::console_color_white : epee::console_color_default, true); std::cout << s << std::endl; if (emphasis) epee::reset_console_color(); },
|
||||
|
|
|
@ -85,8 +85,8 @@ static void make_M_2_wallet(tools::wallet2 &wallet0, tools::wallet2 &wallet1, un
|
|||
std::string mi0 = wallet0.get_multisig_info();
|
||||
std::string mi1 = wallet1.get_multisig_info();
|
||||
|
||||
ASSERT_TRUE(wallet0.verify_multisig_info(mi1, sk0[0], pk0[0]));
|
||||
ASSERT_TRUE(wallet1.verify_multisig_info(mi0, sk1[0], pk1[0]));
|
||||
ASSERT_TRUE(tools::wallet2::verify_multisig_info(mi1, sk0[0], pk0[0]));
|
||||
ASSERT_TRUE(tools::wallet2::verify_multisig_info(mi0, sk1[0], pk1[0]));
|
||||
|
||||
ASSERT_FALSE(wallet0.multisig() || wallet1.multisig());
|
||||
wallet0.make_multisig("", sk0, pk0, M);
|
||||
|
@ -118,12 +118,12 @@ static void make_M_3_wallet(tools::wallet2 &wallet0, tools::wallet2 &wallet1, to
|
|||
std::string mi1 = wallet1.get_multisig_info();
|
||||
std::string mi2 = wallet2.get_multisig_info();
|
||||
|
||||
ASSERT_TRUE(wallet0.verify_multisig_info(mi1, sk0[0], pk0[0]));
|
||||
ASSERT_TRUE(wallet0.verify_multisig_info(mi2, sk0[1], pk0[1]));
|
||||
ASSERT_TRUE(wallet1.verify_multisig_info(mi0, sk1[0], pk1[0]));
|
||||
ASSERT_TRUE(wallet1.verify_multisig_info(mi2, sk1[1], pk1[1]));
|
||||
ASSERT_TRUE(wallet2.verify_multisig_info(mi0, sk2[0], pk2[0]));
|
||||
ASSERT_TRUE(wallet2.verify_multisig_info(mi1, sk2[1], pk2[1]));
|
||||
ASSERT_TRUE(tools::wallet2::verify_multisig_info(mi1, sk0[0], pk0[0]));
|
||||
ASSERT_TRUE(tools::wallet2::verify_multisig_info(mi2, sk0[1], pk0[1]));
|
||||
ASSERT_TRUE(tools::wallet2::verify_multisig_info(mi0, sk1[0], pk1[0]));
|
||||
ASSERT_TRUE(tools::wallet2::verify_multisig_info(mi2, sk1[1], pk1[1]));
|
||||
ASSERT_TRUE(tools::wallet2::verify_multisig_info(mi0, sk2[0], pk2[0]));
|
||||
ASSERT_TRUE(tools::wallet2::verify_multisig_info(mi1, sk2[1], pk2[1]));
|
||||
|
||||
// not implemented yet
|
||||
if (M < 3)
|
||||
|
|
Loading…
Reference in a new issue