diff options
Diffstat (limited to 'src/cryptonote_core')
-rw-r--r-- | src/cryptonote_core/account.cpp | 2 | ||||
-rw-r--r-- | src/cryptonote_core/account.h | 2 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_basic.h | 1 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_basic_impl.cpp | 8 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_basic_impl.h | 11 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_format_utils.cpp | 130 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_format_utils.h | 5 | ||||
-rw-r--r-- | src/cryptonote_core/tx_extra.h | 1 |
8 files changed, 151 insertions, 9 deletions
diff --git a/src/cryptonote_core/account.cpp b/src/cryptonote_core/account.cpp index eb79f5949..fe8dbd1e8 100644 --- a/src/cryptonote_core/account.cpp +++ b/src/cryptonote_core/account.cpp @@ -120,7 +120,7 @@ DISABLE_VS_WARNINGS(4244 4345) return get_account_address_as_str(testnet, m_keys.m_account_address); } //----------------------------------------------------------------- - std::string account_base::get_public_integrated_address_str(const crypto::hash &payment_id, bool testnet) const + std::string account_base::get_public_integrated_address_str(const crypto::hash8 &payment_id, bool testnet) const { //TODO: change this code into base 58 return get_account_integrated_address_as_str(testnet, m_keys.m_account_address, payment_id); diff --git a/src/cryptonote_core/account.h b/src/cryptonote_core/account.h index 088363bf1..732645ee4 100644 --- a/src/cryptonote_core/account.h +++ b/src/cryptonote_core/account.h @@ -61,7 +61,7 @@ namespace cryptonote void create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey); const account_keys& get_keys() const; std::string get_public_address_str(bool testnet) const; - std::string get_public_integrated_address_str(const crypto::hash &payment_id, bool testnet) const; + std::string get_public_integrated_address_str(const crypto::hash8 &payment_id, bool testnet) const; uint64_t get_createtime() const { return m_creation_timestamp; } void set_createtime(uint64_t val) { m_creation_timestamp = val; } diff --git a/src/cryptonote_core/cryptonote_basic.h b/src/cryptonote_core/cryptonote_basic.h index 2be76c0de..07745bf0d 100644 --- a/src/cryptonote_core/cryptonote_basic.h +++ b/src/cryptonote_core/cryptonote_basic.h @@ -57,6 +57,7 @@ namespace cryptonote { const static crypto::hash null_hash = AUTO_VAL_INIT(null_hash); + const static crypto::hash8 null_hash8 = AUTO_VAL_INIT(null_hash8); const static crypto::public_key null_pkey = AUTO_VAL_INIT(null_pkey); typedef std::vector<crypto::signature> ring_signature; diff --git a/src/cryptonote_core/cryptonote_basic_impl.cpp b/src/cryptonote_core/cryptonote_basic_impl.cpp index 1319a2ef9..bd0b8a304 100644 --- a/src/cryptonote_core/cryptonote_basic_impl.cpp +++ b/src/cryptonote_core/cryptonote_basic_impl.cpp @@ -46,7 +46,7 @@ namespace cryptonote { struct integrated_address { account_public_address adr; - crypto::hash payment_id; + crypto::hash8 payment_id; BEGIN_SERIALIZE_OBJECT() FIELD(adr) @@ -150,7 +150,7 @@ namespace cryptonote { std::string get_account_integrated_address_as_str( bool testnet , account_public_address const & adr - , crypto::hash const & payment_id + , crypto::hash8 const & payment_id ) { uint64_t integrated_address_prefix = testnet ? @@ -176,7 +176,7 @@ namespace cryptonote { bool get_account_integrated_address_from_str( account_public_address& adr , bool& has_payment_id - , crypto::hash& payment_id + , crypto::hash8& payment_id , bool testnet , std::string const & str ) @@ -278,7 +278,7 @@ namespace cryptonote { ) { bool has_payment_id; - crypto::hash payment_id; + crypto::hash8 payment_id; return get_account_integrated_address_from_str(adr, has_payment_id, payment_id, testnet, str); } diff --git a/src/cryptonote_core/cryptonote_basic_impl.h b/src/cryptonote_core/cryptonote_basic_impl.h index 87d6f1024..5c442d558 100644 --- a/src/cryptonote_core/cryptonote_basic_impl.h +++ b/src/cryptonote_core/cryptonote_basic_impl.h @@ -60,7 +60,7 @@ namespace cryptonote { { uint8_t m_ver; account_public_address m_address; - crypto::hash payment_id; + crypto::hash8 payment_id; uint8_t check_sum; }; #pragma pack (pop) @@ -83,13 +83,13 @@ namespace cryptonote { std::string get_account_integrated_address_as_str( bool testnet , const account_public_address& adr - , const crypto::hash& payment_id + , const crypto::hash8& payment_id ); bool get_account_integrated_address_from_str( account_public_address& adr , bool& has_payment_id - , crypto::hash& payment_id + , crypto::hash8& payment_id , bool testnet , const std::string& str ); @@ -110,6 +110,10 @@ template <class T> std::ostream &print256(std::ostream &o, const T &v) { return o << "<" << epee::string_tools::pod_to_hex(v) << ">"; } +template <class T> +std::ostream &print64(std::ostream &o, const T &v) { + return o << "<" << epee::string_tools::pod_to_hex(v) << ">"; +} bool parse_hash256(const std::string str_hash, crypto::hash& hash); @@ -120,4 +124,5 @@ namespace crypto { inline std::ostream &operator <<(std::ostream &o, const crypto::key_image &v) { return print256(o, v); } inline std::ostream &operator <<(std::ostream &o, const crypto::signature &v) { return print256(o, v); } inline std::ostream &operator <<(std::ostream &o, const crypto::hash &v) { return print256(o, v); } + inline std::ostream &operator <<(std::ostream &o, const crypto::hash8 &v) { return print64(o, v); } } diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index 1b21894a0..af8e703bf 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -38,6 +38,8 @@ using namespace epee; #include "crypto/crypto.h" #include "crypto/hash.h" +#define ENCRYPTED_PAYMENT_ID_TAIL 0x8d + namespace cryptonote { //--------------------------------------------------------------- @@ -303,6 +305,35 @@ namespace cryptonote return true; } //--------------------------------------------------------------- + bool remove_extra_nonce_tx_extra(std::vector<uint8_t>& tx_extra) + { + std::string extra_str(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size()); + std::istringstream iss(extra_str); + binary_archive<false> ar(iss); + std::ostringstream oss; + binary_archive<true> newar(oss); + + bool eof = false; + while (!eof) + { + tx_extra_field field; + bool r = ::do_serialize(ar, field); + CHECK_AND_NO_ASSERT_MES(r, false, "failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size()))); + if (field.type() != typeid(tx_extra_nonce)) + ::do_serialize(newar, field); + + std::ios_base::iostate state = iss.rdstate(); + eof = (EOF == iss.peek()); + iss.clear(state); + } + CHECK_AND_NO_ASSERT_MES(::serialization::check_stream_state(ar), false, "failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size()))); + tx_extra.clear(); + std::string s = oss.str(); + tx_extra.reserve(s.size()); + std::copy(s.begin(), s.end(), std::back_inserter(tx_extra)); + return true; + } + //--------------------------------------------------------------- void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id) { extra_nonce.clear(); @@ -311,6 +342,14 @@ namespace cryptonote std::copy(payment_id_ptr, payment_id_ptr + sizeof(payment_id), std::back_inserter(extra_nonce)); } //--------------------------------------------------------------- + void set_encrypted_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash8& payment_id) + { + extra_nonce.clear(); + extra_nonce.push_back(TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID); + const uint8_t* payment_id_ptr = reinterpret_cast<const uint8_t*>(&payment_id); + std::copy(payment_id_ptr, payment_id_ptr + sizeof(payment_id), std::back_inserter(extra_nonce)); + } + //--------------------------------------------------------------- bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id) { if(sizeof(crypto::hash) + 1 != extra_nonce.size()) @@ -321,6 +360,54 @@ namespace cryptonote return true; } //--------------------------------------------------------------- + bool get_encrypted_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash8& payment_id) + { + if(sizeof(crypto::hash8) + 1 != extra_nonce.size()) + return false; + if (TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID != extra_nonce[0]) + return false; + payment_id = *reinterpret_cast<const crypto::hash8*>(extra_nonce.data() + 1); + return true; + } + //--------------------------------------------------------------- + crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const account_keys &sender_keys) + { + if (destinations.empty()) + return null_pkey; + for (size_t n = 1; n < destinations.size(); ++n) + { + if (!memcmp(&destinations[n].addr, &sender_keys.m_account_address, sizeof(destinations[0].addr))) + continue; + if (memcmp(&destinations[n].addr, &destinations[0].addr, sizeof(destinations[0].addr))) + return null_pkey; + } + return destinations[0].addr.m_view_public_key; + } + //--------------------------------------------------------------- + bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) + { + crypto::key_derivation derivation; + crypto::hash hash; + char data[33]; /* A hash, and an extra byte */ + + if (!generate_key_derivation(public_key, secret_key, derivation)) + return false; + + memcpy(data, &derivation, 32); + data[32] = ENCRYPTED_PAYMENT_ID_TAIL; + cn_fast_hash(data, 33, hash); + + for (size_t b = 0; b < 8; ++b) + payment_id.data[b] ^= hash.data[b]; + + return true; + } + bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) + { + // Encryption and decryption are the same operation (xor with a key) + return encrypt_payment_id(payment_id, public_key, secret_key); + } + //--------------------------------------------------------------- bool construct_tx(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time) { tx.vin.clear(); @@ -334,6 +421,49 @@ namespace cryptonote keypair txkey = keypair::generate(); add_tx_pub_key_to_extra(tx, txkey.pub); + // if we have a stealth payment id, find it and encrypt it with the tx key now + std::vector<tx_extra_field> tx_extra_fields; + if (parse_tx_extra(tx.extra, tx_extra_fields)) + { + tx_extra_nonce extra_nonce; + if (find_tx_extra_field_by_type(tx_extra_fields, extra_nonce)) + { + crypto::hash8 payment_id = null_hash8; + if (get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id)) + { + LOG_PRINT_L2("Encrypting payment id " << payment_id); + crypto::key_derivation derivation; + crypto::public_key view_key_pub = get_destination_view_key_pub(destinations, sender_account_keys); + if (view_key_pub == null_pkey) + { + LOG_ERROR("Destinations have to have exactly one output to support encrypted payment ids"); + return false; + } + + if (!encrypt_payment_id(payment_id, view_key_pub, txkey.sec)) + { + LOG_ERROR("Failed to encrypt payment id"); + return false; + } + + std::string extra_nonce; + set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id); + remove_extra_nonce_tx_extra(tx.extra); + if (!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce)) + { + LOG_ERROR("Failed to add encrypted payment id to tx extra"); + return false; + } + LOG_PRINT_L1("Encrypted payment ID: " << payment_id); + } + } + } + else + { + LOG_ERROR("Failed to parse tx extra"); + return false; + } + struct input_generation_context_data { keypair in_ephemeral; diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h index fd785aafd..319205368 100644 --- a/src/cryptonote_core/cryptonote_format_utils.h +++ b/src/cryptonote_core/cryptonote_format_utils.h @@ -45,6 +45,8 @@ namespace cryptonote bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash); bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx); bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins, size_t current_block_size, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 1); + bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key); + bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key); struct tx_source_entry { @@ -85,8 +87,11 @@ namespace cryptonote crypto::public_key get_tx_pub_key_from_extra(const transaction& tx); bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key); bool add_extra_nonce_to_tx_extra(std::vector<uint8_t>& tx_extra, const blobdata& extra_nonce); + bool remove_extra_nonce_tx_extra(std::vector<uint8_t>& tx_extra); void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id); + void set_encrypted_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash8& payment_id); bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id); + bool get_encrypted_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash8& payment_id); bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, size_t output_index); bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<size_t>& outs, uint64_t& money_transfered); bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered); diff --git a/src/cryptonote_core/tx_extra.h b/src/cryptonote_core/tx_extra.h index ccfe4d1d9..012f41593 100644 --- a/src/cryptonote_core/tx_extra.h +++ b/src/cryptonote_core/tx_extra.h @@ -40,6 +40,7 @@ #define TX_EXTRA_MERGE_MINING_TAG 0x03 #define TX_EXTRA_NONCE_PAYMENT_ID 0x00 +#define TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID 0x01 namespace cryptonote { |