From e36f5b6021eb541d72fee4b2d5643ba42fd4d9dd Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 4 Nov 2017 10:39:17 +0000 Subject: [PATCH] Match surae's recommendation to derive multisig keys --- src/multisig/multisig.cpp | 33 +++++++++++++++++++------------ src/multisig/multisig.h | 1 + src/simplewallet/simplewallet.cpp | 5 +++-- src/wallet/wallet2.cpp | 31 +++++++++++++++-------------- src/wallet/wallet_rpc_server.cpp | 6 +++--- tests/core_tests/chaingen.h | 10 ++++++---- 6 files changed, 49 insertions(+), 37 deletions(-) diff --git a/src/multisig/multisig.cpp b/src/multisig/multisig.cpp index a99f66e64..39d0e1c4b 100644 --- a/src/multisig/multisig.cpp +++ b/src/multisig/multisig.cpp @@ -39,18 +39,29 @@ using namespace std; +static const rct::key multisig_salt = { {'M', 'u', 'l', 't' , 'i', 's', 'i', 'g', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; + namespace cryptonote { + //----------------------------------------------------------------- + crypto::secret_key get_multisig_blinded_secret_key(const crypto::secret_key &key) + { + rct::keyV data; + data.push_back(rct::sk2rct(key)); + data.push_back(multisig_salt); + return rct::rct2sk(rct::hash_to_scalar(data)); + } //----------------------------------------------------------------- void generate_multisig_N_N(const account_keys &keys, const std::vector &spend_keys, std::vector &multisig_keys, rct::key &spend_skey, rct::key &spend_pkey) { // the multisig spend public key is the sum of all spend public keys multisig_keys.clear(); - spend_pkey = rct::pk2rct(keys.m_account_address.m_spend_public_key); + const crypto::secret_key spend_secret_key = get_multisig_blinded_secret_key(keys.m_spend_secret_key); + CHECK_AND_ASSERT_THROW_MES(crypto::secret_key_to_public_key(spend_secret_key, (crypto::public_key&)spend_pkey), "Failed to derive public key"); for (const auto &k: spend_keys) rct::addKeys(spend_pkey, spend_pkey, rct::pk2rct(k)); - multisig_keys.push_back(keys.m_spend_secret_key); - spend_skey = rct::sk2rct(keys.m_spend_secret_key); + multisig_keys.push_back(spend_secret_key); + spend_skey = rct::sk2rct(spend_secret_key); } //----------------------------------------------------------------- void generate_multisig_N1_N(const account_keys &keys, const std::vector &spend_keys, std::vector &multisig_keys, rct::key &spend_skey, rct::key &spend_pkey) @@ -60,23 +71,19 @@ namespace cryptonote spend_skey = rct::zero(); // create all our composite private keys + crypto::secret_key blinded_skey = get_multisig_blinded_secret_key(keys.m_spend_secret_key); for (const auto &k: spend_keys) { - rct::keyV data; - data.push_back(rct::scalarmultKey(rct::pk2rct(k), rct::sk2rct(keys.m_spend_secret_key))); - static const rct::key salt = { {'M', 'u', 'l', 't' , 'i', 's', 'i', 'g' , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 } }; - data.push_back(salt); - rct::key msk = rct::hash_to_scalar(data); - multisig_keys.push_back(rct::rct2sk(msk)); - sc_add(spend_skey.bytes, spend_skey.bytes, msk.bytes); + rct::key sk = rct::scalarmultKey(rct::pk2rct(k), rct::sk2rct(blinded_skey)); + crypto::secret_key msk = get_multisig_blinded_secret_key(rct::rct2sk(sk)); + multisig_keys.push_back(msk); + sc_add(spend_skey.bytes, spend_skey.bytes, (const unsigned char*)msk.data); } } //----------------------------------------------------------------- crypto::secret_key generate_multisig_view_secret_key(const crypto::secret_key &skey, const std::vector &skeys) { - crypto::hash hash; - crypto::cn_fast_hash(&skey, sizeof(crypto::hash), hash); - rct::key view_skey = rct::hash2rct(hash); + rct::key view_skey = rct::sk2rct(get_multisig_blinded_secret_key(skey)); for (const auto &k: skeys) sc_add(view_skey.bytes, view_skey.bytes, rct::sk2rct(k).bytes); return rct::rct2sk(view_skey); diff --git a/src/multisig/multisig.h b/src/multisig/multisig.h index 5cb469c1b..f29b47987 100644 --- a/src/multisig/multisig.h +++ b/src/multisig/multisig.h @@ -38,6 +38,7 @@ namespace cryptonote { struct account_keys; + crypto::secret_key get_multisig_blinded_secret_key(const crypto::secret_key &key); void generate_multisig_N_N(const account_keys &keys, const std::vector &spend_keys, std::vector &multisig_keys, rct::key &spend_skey, rct::key &spend_pkey); void generate_multisig_N1_N(const account_keys &keys, const std::vector &spend_keys, std::vector &multisig_keys, rct::key &spend_skey, rct::key &spend_pkey); crypto::secret_key generate_multisig_view_secret_key(const crypto::secret_key &skey, const std::vector &skeys); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 98d7ea14f..145d90d91 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -60,6 +60,7 @@ #include "rapidjson/document.h" #include "common/json_util.h" #include "ringct/rctSigs.h" +#include "multisig/multisig.h" #include "wallet/wallet_args.h" #include @@ -801,8 +802,8 @@ bool simple_wallet::make_multisig(const std::vector &args) } // people may include their own, weed it out - const crypto::secret_key local_skey = m_wallet->get_account().get_keys().m_view_secret_key; - const crypto::public_key local_pkey = m_wallet->get_account().get_keys().m_account_address.m_spend_public_key; + const crypto::secret_key local_skey = cryptonote::get_multisig_blinded_secret_key(m_wallet->get_account().get_keys().m_view_secret_key); + const crypto::public_key local_pkey = m_wallet->get_multisig_signer_public_key(m_wallet->get_account().get_keys().m_spend_secret_key); for (size_t i = 0; i < secret_keys.size(); ++i) { if (secret_keys[i] == local_skey) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 013ad6a75..29ca3dd2f 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2830,8 +2830,6 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password, // We need an extra step, so we package all the composite public keys // we know about, and make a signed string out of them std::string data; - const crypto::public_key &pkey = get_account().get_keys().m_account_address.m_spend_public_key; - data += std::string((const char *)&pkey, sizeof(crypto::public_key)); const crypto::public_key signer = get_multisig_signer_public_key(rct::rct2sk(spend_skey)); data += std::string((const char *)&signer, sizeof(crypto::public_key)); @@ -2844,7 +2842,7 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password, data.resize(data.size() + sizeof(crypto::signature)); crypto::cn_fast_hash(data.data(), data.size() - sizeof(signature), hash); crypto::signature &signature = *(crypto::signature*)&data[data.size() - sizeof(crypto::signature)]; - crypto::generate_signature(hash, pkey, get_account().get_keys().m_spend_secret_key, signature); + crypto::generate_signature(hash, signer, get_multisig_blinded_secret_key(rct::rct2sk(spend_skey)), signature); extra_multisig_info = std::string("MultisigxV1") + tools::base58::encode(data); } @@ -2958,19 +2956,18 @@ bool wallet2::finalize_multisig(const epee::wipeable_string &password, const std std::string wallet2::get_multisig_info() const { // It's a signed package of private view key and public spend key - const crypto::secret_key &skey = get_account().get_keys().m_view_secret_key; - const crypto::public_key &pkey = get_account().get_keys().m_account_address.m_spend_public_key; + const crypto::secret_key skey = cryptonote::get_multisig_blinded_secret_key(get_account().get_keys().m_view_secret_key); + const crypto::public_key pkey = get_multisig_signer_public_key(get_account().get_keys().m_spend_secret_key); crypto::hash hash; std::string data; - crypto::cn_fast_hash(&skey, sizeof(crypto::secret_key), hash); - data += std::string((const char *)&hash, sizeof(crypto::hash)); + data += std::string((const char *)&skey, sizeof(crypto::secret_key)); data += std::string((const char *)&pkey, sizeof(crypto::public_key)); data.resize(data.size() + sizeof(crypto::signature)); crypto::cn_fast_hash(data.data(), data.size() - sizeof(signature), hash); crypto::signature &signature = *(crypto::signature*)&data[data.size() - sizeof(crypto::signature)]; - crypto::generate_signature(hash, pkey, get_account().get_keys().m_spend_secret_key, signature); + crypto::generate_signature(hash, pkey, get_multisig_blinded_secret_key(get_account().get_keys().m_spend_secret_key), signature); return std::string("MultisigV1") + tools::base58::encode(data); } @@ -3027,28 +3024,26 @@ bool wallet2::verify_extra_multisig_info(const std::string &data, std::unordered MERROR("Multisig info decoding error"); return false; } - if (decoded.size() < sizeof(crypto::public_key) + sizeof(crypto::public_key) + sizeof(crypto::signature)) + if (decoded.size() < sizeof(crypto::public_key) + sizeof(crypto::signature)) { MERROR("Multisig info is corrupt"); return false; } - if ((decoded.size() - (sizeof(crypto::public_key) + sizeof(crypto::public_key) + sizeof(crypto::signature))) % sizeof(crypto::public_key)) + if ((decoded.size() - (sizeof(crypto::public_key) + sizeof(crypto::signature))) % sizeof(crypto::public_key)) { MERROR("Multisig info is corrupt"); return false; } - const size_t n_keys = (decoded.size() - (sizeof(crypto::public_key) + sizeof(crypto::public_key) + sizeof(crypto::signature))) / sizeof(crypto::public_key); + const size_t n_keys = (decoded.size() - (sizeof(crypto::public_key) + sizeof(crypto::signature))) / sizeof(crypto::public_key); size_t offset = 0; - const crypto::public_key &pkey = *(const crypto::public_key*)(decoded.data() + offset); - offset += sizeof(pkey); signer = *(const crypto::public_key*)(decoded.data() + offset); offset += sizeof(signer); const crypto::signature &signature = *(const crypto::signature*)(decoded.data() + offset + n_keys * sizeof(crypto::public_key)); crypto::hash hash; crypto::cn_fast_hash(decoded.data(), decoded.size() - sizeof(signature), hash); - if (!crypto::check_signature(hash, pkey, signature)) + if (!crypto::check_signature(hash, signer, signature)) { MERROR("Multisig info signature is invalid"); return false; @@ -8313,13 +8308,19 @@ size_t wallet2::import_outputs(const std::vectorget_account().get_keys().m_view_secret_key, sizeof(crypto::secret_key), hash); + crypto::secret_key local_skey = cryptonote::get_multisig_blinded_secret_key(m_wallet->get_account().get_keys().m_view_secret_key); for (size_t i = 0; i < secret_keys.size(); ++i) { - if (rct::sk2rct(secret_keys[i]) == rct::hash2rct(hash)) + if (rct::sk2rct(secret_keys[i]) == rct::sk2rct(local_skey)) { secret_keys[i] = secret_keys.back(); public_keys[i] = public_keys.back(); diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index 939b88109..9fed95183 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -521,10 +521,12 @@ inline bool do_replay_file(const std::string& filename) { \ if (msidx_inner != msidx) \ { \ - crypto::hash vkh; \ - crypto::cn_fast_hash(&account[msidx_inner].get_keys().m_view_secret_key, sizeof(crypto::secret_key), vkh); \ - view_keys[msidx].push_back((const crypto::secret_key&)vkh); \ - spend_keys[msidx].push_back(account[msidx_inner].get_keys().m_account_address.m_spend_public_key); \ + crypto::secret_key vkh = cryptonote::get_multisig_blinded_secret_key(account[msidx_inner].get_keys().m_view_secret_key); \ + view_keys[msidx].push_back(vkh); \ + crypto::secret_key skh = cryptonote::get_multisig_blinded_secret_key(account[msidx_inner].get_keys().m_spend_secret_key); \ + crypto::public_key pskh; \ + crypto::secret_key_to_public_key(skh, pskh); \ + spend_keys[msidx].push_back(pskh); \ } \ } \ } \