aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormoneromooo-monero <moneromooo-monero@users.noreply.github.com>2017-10-21 12:14:31 +0100
committermoneromooo-monero <moneromooo-monero@users.noreply.github.com>2017-12-17 16:12:27 +0000
commitfa5697127f5a99ddd20311cec8180f6a89b31ceb (patch)
tree84e8e300a69270b1d61a6c3694caee4682f48ffb /src
parentsimplewallet: add export_raw_multisig command (diff)
downloadmonero-fa5697127f5a99ddd20311cec8180f6a89b31ceb.tar.xz
make multisig work with subaddresses
Thanks to kenshi84 for help getting this work
Diffstat (limited to 'src')
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.cpp53
-rw-r--r--src/cryptonote_core/cryptonote_tx_utils.cpp17
-rw-r--r--src/cryptonote_core/cryptonote_tx_utils.h6
-rw-r--r--src/multisig/multisig.cpp28
-rw-r--r--src/multisig/multisig.h6
-rw-r--r--src/wallet/wallet2.cpp42
-rw-r--r--src/wallet/wallet2.h1
7 files changed, 78 insertions, 75 deletions
diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp
index a22c3bdea..8f7ab94db 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.cpp
+++ b/src/cryptonote_basic/cryptonote_format_utils.cpp
@@ -80,6 +80,31 @@ static std::atomic<uint64_t> tx_hashes_cached_count(0);
static std::atomic<uint64_t> block_hashes_calculated_count(0);
static std::atomic<uint64_t> block_hashes_cached_count(0);
+#define CHECK_AND_ASSERT_THROW_MES_L1(expr, message) {if(!(expr)) {MWARNING(message); throw std::runtime_error(message);}}
+
+namespace cryptonote
+{
+ static inline unsigned char *operator &(ec_point &point) {
+ return &reinterpret_cast<unsigned char &>(point);
+ }
+ static inline const unsigned char *operator &(const ec_point &point) {
+ return &reinterpret_cast<const unsigned char &>(point);
+ }
+
+ // a copy of rct::addKeys, since we can't link to libringct to avoid circular dependencies
+ static void add_public_key(crypto::public_key &AB, const crypto::public_key &A, const crypto::public_key &B) {
+ ge_p3 B2, A2;
+ CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&B2, &B) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
+ CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&A2, &A) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
+ ge_cached tmp2;
+ ge_p3_to_cached(&tmp2, &B2);
+ ge_p1p1 tmp3;
+ ge_add(&tmp3, &A2, &tmp2);
+ ge_p1p1_to_p3(&A2, &tmp3);
+ ge_p3_tobytes(&AB, &A2);
+ }
+}
+
namespace cryptonote
{
//---------------------------------------------------------------
@@ -182,6 +207,7 @@ namespace cryptonote
crypto::derive_secret_key(recv_derivation, real_output_index, ack.m_spend_secret_key, scalar_step1); // computes Hs(a*R || idx) + b
// step 2: add Hs(a || index_major || index_minor)
+ crypto::secret_key subaddr_sk;
crypto::secret_key scalar_step2;
if (received_index.is_zero())
{
@@ -189,13 +215,32 @@ namespace cryptonote
}
else
{
- crypto::secret_key m = get_subaddress_secret_key(ack.m_view_secret_key, received_index);
- sc_add((unsigned char*)&scalar_step2, (unsigned char*)&scalar_step1, (unsigned char*)&m);
+ subaddr_sk = get_subaddress_secret_key(ack.m_view_secret_key, received_index);
+ sc_add((unsigned char*)&scalar_step2, (unsigned char*)&scalar_step1, (unsigned char*)&subaddr_sk);
}
in_ephemeral.sec = scalar_step2;
- crypto::secret_key_to_public_key(in_ephemeral.sec, in_ephemeral.pub);
- CHECK_AND_ASSERT_MES(in_ephemeral.pub == out_key, false, "key image helper precomp: given output pubkey doesn't match the derived one");
+
+ if (ack.m_multisig_keys.empty())
+ {
+ // when not in multisig, we know the full spend secret key, so the output pubkey can be obtained by scalarmultBase
+ CHECK_AND_ASSERT_MES(crypto::secret_key_to_public_key(in_ephemeral.sec, in_ephemeral.pub), false, "Failed to derive public key");
+ }
+ else
+ {
+ // when in multisig, we only know the partial spend secret key. but we do know the full spend public key, so the output pubkey can be obtained by using the standard CN key derivation
+ CHECK_AND_ASSERT_MES(crypto::derive_public_key(recv_derivation, real_output_index, ack.m_account_address.m_spend_public_key, in_ephemeral.pub), false, "Failed to derive public key");
+ // and don't forget to add the contribution from the subaddress part
+ if (!received_index.is_zero())
+ {
+ crypto::public_key subaddr_pk;
+ CHECK_AND_ASSERT_MES(crypto::secret_key_to_public_key(subaddr_sk, subaddr_pk), false, "Failed to derive public key");
+ add_public_key(in_ephemeral.pub, in_ephemeral.pub, subaddr_pk);
+ }
+ }
+
+ CHECK_AND_ASSERT_MES(in_ephemeral.pub == out_key,
+ false, "key image helper precomp: given output pubkey doesn't match the derived one");
}
crypto::generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki);
diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp
index fb1f972b3..89f24a4d4 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.cpp
+++ b/src/cryptonote_core/cryptonote_tx_utils.cpp
@@ -269,24 +269,15 @@ namespace cryptonote
in_contexts.push_back(input_generation_context_data());
keypair& in_ephemeral = in_contexts.back().in_ephemeral;
crypto::key_image img;
- bool r;
- if (msout)
- {
- r = generate_key_image_helper_old(sender_account_keys, src_entr.real_out_tx_key, src_entr.real_output_in_tx_index, in_ephemeral, img);
- }
- else
- {
- const auto& out_key = reinterpret_cast<const crypto::public_key&>(src_entr.outputs[src_entr.real_output].second.dest);
- r = generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral, img);
- }
- if (!r)
+ const auto& out_key = reinterpret_cast<const crypto::public_key&>(src_entr.outputs[src_entr.real_output].second.dest);
+ if(!generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral, img))
{
LOG_ERROR("Key image generation failed!");
return false;
}
- //check that derivated key is equal with real output key
- if( !(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].second.dest) )
+ //check that derivated key is equal with real output key (if non multisig)
+ if(!msout && !(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].second.dest) )
{
LOG_ERROR("derived public key mismatch with output public key at index " << idx << ", real out " << src_entr.real_output << "! "<< ENDL << "derived_key:"
<< string_tools::pod_to_hex(in_ephemeral.pub) << ENDL << "real output_public_key:"
diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h
index 2b6cf26db..5947522e2 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.h
+++ b/src/cryptonote_core/cryptonote_tx_utils.h
@@ -64,6 +64,7 @@ namespace cryptonote
FIELD(amount)
FIELD(rct)
FIELD(mask)
+ FIELD(multisig_kLRki)
if (real_output >= outputs.size())
return false;
@@ -100,7 +101,7 @@ namespace cryptonote
}
-BOOST_CLASS_VERSION(cryptonote::tx_source_entry, 0)
+BOOST_CLASS_VERSION(cryptonote::tx_source_entry, 1)
BOOST_CLASS_VERSION(cryptonote::tx_destination_entry, 1)
namespace boost
@@ -117,7 +118,10 @@ namespace boost
a & x.amount;
a & x.rct;
a & x.mask;
+ if (ver < 1)
+ return;
a & x.multisig_kLRki;
+ a & x.real_out_additional_tx_keys;
}
template <class Archive>
diff --git a/src/multisig/multisig.cpp b/src/multisig/multisig.cpp
index 0a9933b13..a99f66e64 100644
--- a/src/multisig/multisig.cpp
+++ b/src/multisig/multisig.cpp
@@ -42,21 +42,6 @@ using namespace std;
namespace cryptonote
{
//-----------------------------------------------------------------
- bool generate_key_image_helper_old(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki)
- {
- crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation);
- bool r = crypto::generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation);
- CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to generate_key_derivation(" << tx_public_key << ", " << ack.m_view_secret_key << ")");
-
- r = crypto::derive_public_key(recv_derivation, real_output_index, ack.m_account_address.m_spend_public_key, in_ephemeral.pub);
- CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to derive_public_key(" << recv_derivation << ", " << real_output_index << ", " << ack.m_account_address.m_spend_public_key << ")");
-
- crypto::derive_secret_key(recv_derivation, real_output_index, ack.m_spend_secret_key, in_ephemeral.sec);
-
- crypto::generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki);
- return true;
- }
- //-----------------------------------------------------------------
void generate_multisig_N_N(const account_keys &keys, const std::vector<crypto::public_key> &spend_keys, std::vector<crypto::secret_key> &multisig_keys, rct::key &spend_skey, rct::key &spend_pkey)
{
// the multisig spend public key is the sum of all spend public keys
@@ -107,14 +92,11 @@ namespace cryptonote
return rct::rct2pk(spend_public_key);
}
//-----------------------------------------------------------------
- bool generate_multisig_key_image(const account_keys &keys, const crypto::public_key& tx_public_key, size_t real_output_index, cryptonote::keypair& in_ephemeral, crypto::key_image& ki, size_t multisig_key_index)
+ bool generate_multisig_key_image(const account_keys &keys, size_t multisig_key_index, const crypto::public_key& out_key, crypto::key_image& ki)
{
if (multisig_key_index >= keys.m_multisig_keys.size())
return false;
- if (!cryptonote::generate_key_image_helper_old(keys, tx_public_key, real_output_index, in_ephemeral, ki))
- return false;
- // we got the ephemeral keypair, but the key image isn't right as it's done as per our private spend key, which is multisig
- crypto::generate_key_image(in_ephemeral.pub, keys.m_multisig_keys[multisig_key_index], ki);
+ crypto::generate_key_image(out_key, keys.m_multisig_keys[multisig_key_index], ki);
return true;
}
//-----------------------------------------------------------------
@@ -124,16 +106,16 @@ namespace cryptonote
crypto::generate_key_image(pkey, k, (crypto::key_image&)R);
}
//-----------------------------------------------------------------
- bool generate_multisig_composite_key_image(const account_keys &keys, const crypto::public_key &tx_public_key, size_t real_output_index, const std::vector<crypto::key_image> &pkis, crypto::key_image &ki)
+ bool generate_multisig_composite_key_image(const account_keys &keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key &tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, const std::vector<crypto::key_image> &pkis, crypto::key_image &ki)
{
cryptonote::keypair in_ephemeral;
- if (!cryptonote::generate_key_image_helper_old(keys, tx_public_key, real_output_index, in_ephemeral, ki))
+ if (!cryptonote::generate_key_image_helper(keys, subaddresses, out_key, tx_public_key, additional_tx_public_keys, real_output_index, in_ephemeral, ki))
return false;
std::unordered_set<crypto::key_image> used;
for (size_t m = 0; m < keys.m_multisig_keys.size(); ++m)
{
crypto::key_image pki;
- bool r = cryptonote::generate_multisig_key_image(keys, tx_public_key, real_output_index, in_ephemeral, pki, m);
+ bool r = cryptonote::generate_multisig_key_image(keys, m, out_key, pki);
if (!r)
return false;
used.insert(pki);
diff --git a/src/multisig/multisig.h b/src/multisig/multisig.h
index c5312182b..5cb469c1b 100644
--- a/src/multisig/multisig.h
+++ b/src/multisig/multisig.h
@@ -38,13 +38,11 @@ namespace cryptonote
{
struct account_keys;
- bool generate_key_image_helper_old(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki);
-
void generate_multisig_N_N(const account_keys &keys, const std::vector<crypto::public_key> &spend_keys, std::vector<crypto::secret_key> &multisig_keys, rct::key &spend_skey, rct::key &spend_pkey);
void generate_multisig_N1_N(const account_keys &keys, const std::vector<crypto::public_key> &spend_keys, std::vector<crypto::secret_key> &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<crypto::secret_key> &skeys);
crypto::public_key generate_multisig_N1_N_spend_public_key(const std::vector<crypto::public_key> &pkeys);
- bool generate_multisig_key_image(const account_keys &keys, const crypto::public_key& tx_public_key, size_t real_output_index, cryptonote::keypair& in_ephemeral, crypto::key_image& ki, size_t multisig_key_index);
+ bool generate_multisig_key_image(const account_keys &keys, size_t multisig_key_index, const crypto::public_key& out_key, crypto::key_image& ki);
void generate_multisig_LR(const crypto::public_key pkey, const crypto::secret_key &k, crypto::public_key &L, crypto::public_key &R);
- bool generate_multisig_composite_key_image(const account_keys &keys, const crypto::public_key &tx_public_key, size_t real_output_index, const std::vector<crypto::key_image> &pkis, crypto::key_image &ki);
+ bool generate_multisig_composite_key_image(const account_keys &keys, const std::unordered_map<crypto::public_key, cryptonote::subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key &tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, const std::vector<crypto::key_image> &pkis, crypto::key_image &ki);
}
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 9c2587f25..4ad6d852d 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -527,18 +527,6 @@ uint8_t get_bulletproof_fork(bool testnet)
return 255; // TODO
}
-bool wallet_generate_key_image_helper_old(const cryptonote::account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, cryptonote::keypair& in_ephemeral, crypto::key_image& ki, bool multisig_export = false)
-{
- if (!cryptonote::generate_key_image_helper_old(ack, tx_public_key, real_output_index, in_ephemeral, ki))
- return false;
- if (multisig_export)
- {
- // we got the ephemeral keypair, but the key image isn't right as it's done as per our private spend key, which is multisig
- crypto::generate_key_image(in_ephemeral.pub, ack.m_spend_secret_key, ki);
- }
- return true;
-}
-
crypto::hash8 get_short_payment_id(const tools::wallet2::pending_tx &ptx)
{
crypto::hash8 payment_id8 = null_hash8;
@@ -895,26 +883,22 @@ static uint64_t decodeRct(const rct::rctSig & rv, const crypto::key_derivation &
}
}
//----------------------------------------------------------------------------------------------------
-bool wallet2::wallet_generate_key_image_helper_export(const cryptonote::account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, cryptonote::keypair& in_ephemeral, crypto::key_image& ki, size_t multisig_key_index) const
-{
- THROW_WALLET_EXCEPTION_IF(multisig_key_index >= ack.m_multisig_keys.size(), error::wallet_internal_error, "Bad multisig_key_index");
- return cryptonote::generate_multisig_key_image(ack, tx_public_key, real_output_index, in_ephemeral, ki, multisig_key_index);
-}
-//----------------------------------------------------------------------------------------------------
void wallet2::scan_output(const cryptonote::account_keys &keys, const cryptonote::transaction &tx, const crypto::public_key &tx_pub_key, size_t i, tx_scan_info_t &tx_scan_info, int &num_vouts_received, std::unordered_map<cryptonote::subaddress_index, uint64_t> &tx_money_got_in_outs, std::vector<size_t> &outs)
{
- bool r;
+ THROW_WALLET_EXCEPTION_IF(i >= tx.vout.size(), error::wallet_internal_error, "Invalid vout index");
if (m_multisig)
{
- r = wallet_generate_key_image_helper_old(keys, tx_pub_key, i, tx_scan_info.in_ephemeral, tx_scan_info.ki);
+ tx_scan_info.in_ephemeral.pub = boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key;
+ tx_scan_info.in_ephemeral.sec = crypto::null_skey;
+ tx_scan_info.ki = rct::rct2ki(rct::zero());
}
else
{
- r = cryptonote::generate_key_image_helper_precomp(keys, boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key, tx_scan_info.received->derivation, i, tx_scan_info.received->index, tx_scan_info.in_ephemeral, tx_scan_info.ki);
+ bool r = cryptonote::generate_key_image_helper_precomp(keys, boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key, tx_scan_info.received->derivation, i, tx_scan_info.received->index, tx_scan_info.in_ephemeral, tx_scan_info.ki);
+ THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
+ THROW_WALLET_EXCEPTION_IF(tx_scan_info.in_ephemeral.pub != boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key,
+ error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key");
}
- THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
- THROW_WALLET_EXCEPTION_IF(tx_scan_info.in_ephemeral.pub != boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key,
- error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key");
outs.push_back(i);
if (tx_scan_info.money_transfered == 0)
@@ -8373,13 +8357,14 @@ crypto::key_image wallet2::get_multisig_composite_key_image(size_t n) const
CHECK_AND_ASSERT_THROW_MES(n < m_transfers.size(), "Bad output index");
const transfer_details &td = m_transfers[n];
- crypto::public_key tx_key = get_tx_pub_key_from_received_outs(td);
+ const crypto::public_key tx_key = get_tx_pub_key_from_received_outs(td);
+ const std::vector<crypto::public_key> additional_tx_keys = cryptonote::get_additional_tx_pub_keys_from_extra(td.m_tx);
crypto::key_image ki;
std::vector<crypto::key_image> pkis;
for (const auto &info: td.m_multisig_info)
for (const auto &pki: info.m_partial_key_images)
pkis.push_back(pki);
- bool r = cryptonote::generate_multisig_composite_key_image(get_account().get_keys(), tx_key, td.m_internal_output_index, pkis, ki);
+ bool r = cryptonote::generate_multisig_composite_key_image(get_account().get_keys(), m_subaddresses, td.get_public_key(), tx_key, additional_tx_keys, td.m_internal_output_index, pkis, ki);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
return ki;
}
@@ -8394,8 +8379,7 @@ std::vector<tools::wallet2::multisig_info> wallet2::export_multisig()
for (size_t n = 0; n < m_transfers.size(); ++n)
{
transfer_details &td = m_transfers[n];
- crypto::public_key tx_key = get_tx_pub_key_from_received_outs(td);
- cryptonote::keypair in_ephemeral;
+ const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx);
crypto::key_image ki;
td.m_multisig_k.clear();
info[n].m_LR.clear();
@@ -8404,7 +8388,7 @@ std::vector<tools::wallet2::multisig_info> wallet2::export_multisig()
for (size_t m = 0; m < get_account().get_multisig_keys().size(); ++m)
{
// we want to export the partial key image, not the full one, so we can't use td.m_key_image
- bool r = wallet_generate_key_image_helper_export(get_account().get_keys(), tx_key, td.m_internal_output_index, in_ephemeral, ki, m);
+ bool r = generate_multisig_key_image(get_account().get_keys(), m, td.get_public_key(), ki);
CHECK_AND_ASSERT_THROW_MES(r, "Failed to generate key image");
info[n].m_partial_key_images.push_back(ki);
}
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 79199a30c..45f82fa1a 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -977,7 +977,6 @@ namespace tools
void set_unspent(size_t idx);
void get_outs(std::vector<std::vector<get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count);
bool tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, uint64_t global_index, const crypto::public_key& tx_public_key, const rct::key& mask, uint64_t real_index, bool unlocked) const;
- bool wallet_generate_key_image_helper_export(const cryptonote::account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, cryptonote::keypair& in_ephemeral, crypto::key_image& ki, size_t multisig_key_index) const;
crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const;
bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &unused_dust_indices) const;
std::vector<size_t> get_only_rct(const std::vector<size_t> &unused_dust_indices, const std::vector<size_t> &unused_transfers_indices) const;