aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_basic
diff options
context:
space:
mode:
Diffstat (limited to 'src/cryptonote_basic')
-rw-r--r--src/cryptonote_basic/account.cpp15
-rw-r--r--src/cryptonote_basic/account.h5
-rw-r--r--src/cryptonote_basic/cryptonote_boost_serialization.h15
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.cpp53
4 files changed, 84 insertions, 4 deletions
diff --git a/src/cryptonote_basic/account.cpp b/src/cryptonote_basic/account.cpp
index fb832d88e..ddc1fc7fc 100644
--- a/src/cryptonote_basic/account.cpp
+++ b/src/cryptonote_basic/account.cpp
@@ -64,6 +64,7 @@ DISABLE_VS_WARNINGS(4244 4345)
void account_base::forget_spend_key()
{
m_keys.m_spend_secret_key = crypto::secret_key();
+ m_keys.m_multisig_keys.clear();
}
//-----------------------------------------------------------------
crypto::secret_key account_base::generate(const crypto::secret_key& recovery_key, bool recover, bool two_random)
@@ -123,6 +124,20 @@ DISABLE_VS_WARNINGS(4244 4345)
create_from_keys(address, fake, viewkey);
}
//-----------------------------------------------------------------
+ bool account_base::make_multisig(const crypto::secret_key &view_secret_key, const crypto::secret_key &spend_secret_key, const crypto::public_key &spend_public_key, const std::vector<crypto::secret_key> &multisig_keys)
+ {
+ m_keys.m_account_address.m_spend_public_key = spend_public_key;
+ m_keys.m_view_secret_key = view_secret_key;
+ m_keys.m_spend_secret_key = spend_secret_key;
+ m_keys.m_multisig_keys = multisig_keys;
+ return crypto::secret_key_to_public_key(view_secret_key, m_keys.m_account_address.m_view_public_key);
+ }
+ //-----------------------------------------------------------------
+ void account_base::finalize_multisig(const crypto::public_key &spend_public_key)
+ {
+ m_keys.m_account_address.m_spend_public_key = spend_public_key;
+ }
+ //-----------------------------------------------------------------
const account_keys& account_base::get_keys() const
{
return m_keys;
diff --git a/src/cryptonote_basic/account.h b/src/cryptonote_basic/account.h
index e0d5447a2..50af36a9d 100644
--- a/src/cryptonote_basic/account.h
+++ b/src/cryptonote_basic/account.h
@@ -42,11 +42,13 @@ namespace cryptonote
account_public_address m_account_address;
crypto::secret_key m_spend_secret_key;
crypto::secret_key m_view_secret_key;
+ std::vector<crypto::secret_key> m_multisig_keys;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(m_account_address)
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_spend_secret_key)
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_view_secret_key)
+ KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_multisig_keys)
END_KV_SERIALIZE_MAP()
};
@@ -60,6 +62,8 @@ namespace cryptonote
crypto::secret_key generate(const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false, bool two_random = false);
void create_from_keys(const cryptonote::account_public_address& address, const crypto::secret_key& spendkey, const crypto::secret_key& viewkey);
void create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey);
+ bool make_multisig(const crypto::secret_key &view_secret_key, const crypto::secret_key &spend_secret_key, const crypto::public_key &spend_public_key, const std::vector<crypto::secret_key> &multisig_keys);
+ void finalize_multisig(const crypto::public_key &spend_public_key);
const account_keys& get_keys() const;
std::string get_public_address_str(bool testnet) const;
std::string get_public_integrated_address_str(const crypto::hash8 &payment_id, bool testnet) const;
@@ -71,6 +75,7 @@ namespace cryptonote
bool store(const std::string& file_path);
void forget_spend_key();
+ const std::vector<crypto::secret_key> &get_multisig_keys() const { return m_keys.m_multisig_keys; }
template <class t_archive>
inline void serialize(t_archive &a, const unsigned int /*ver*/)
diff --git a/src/cryptonote_basic/cryptonote_boost_serialization.h b/src/cryptonote_basic/cryptonote_boost_serialization.h
index 760edf9b9..ed8239176 100644
--- a/src/cryptonote_basic/cryptonote_boost_serialization.h
+++ b/src/cryptonote_basic/cryptonote_boost_serialization.h
@@ -253,6 +253,21 @@ namespace boost
}
template <class Archive>
+ inline void serialize(Archive &a, rct::multisig_kLRki &x, const boost::serialization::version_type ver)
+ {
+ a & x.k;
+ a & x.L;
+ a & x.R;
+ a & x.ki;
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, rct::multisig_out &x, const boost::serialization::version_type ver)
+ {
+ a & x.c;
+ }
+
+ template <class Archive>
inline typename std::enable_if<Archive::is_loading::value, void>::type serializeOutPk(Archive &a, rct::ctkeyV &outPk_, const boost::serialization::version_type ver)
{
rct::keyV outPk;
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);