From a2d7a5fb49dedd6c7e024701eefc4c0beade1edd Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 9 Aug 2015 10:09:39 +0100 Subject: [PATCH] encrypted payment ids are now 64 bit, instead of 256 bit Pros: - smaller on the blockchain - shorter integrated addresses Cons: - less sparseness - less ability to embed actual information The boolean argument to encrypt payment ids is now gone from the RPC calls, since the decision is made based on the length of the payment id passed. --- src/crypto/hash.h | 5 ++ src/cryptonote_core/account.cpp | 2 +- src/cryptonote_core/account.h | 2 +- src/cryptonote_core/cryptonote_basic.h | 1 + src/cryptonote_core/cryptonote_basic_impl.cpp | 8 +-- src/cryptonote_core/cryptonote_basic_impl.h | 11 +++- .../cryptonote_format_utils.cpp | 44 +++++++++----- src/cryptonote_core/cryptonote_format_utils.h | 10 ++-- src/serialization/crypto.h | 2 + src/simplewallet/simplewallet.cpp | 58 ++++++++++--------- src/wallet/wallet2.cpp | 49 +++++++++++++--- src/wallet/wallet2.h | 2 + src/wallet/wallet_rpc_server.cpp | 58 ++++++++++++------- src/wallet/wallet_rpc_server.h | 2 +- src/wallet/wallet_rpc_server_commands_defs.h | 4 -- 15 files changed, 169 insertions(+), 89 deletions(-) diff --git a/src/crypto/hash.h b/src/crypto/hash.h index 2f91a5358..1ce2f9816 100644 --- a/src/crypto/hash.h +++ b/src/crypto/hash.h @@ -45,9 +45,13 @@ namespace crypto { POD_CLASS hash { char data[HASH_SIZE]; }; + POD_CLASS hash8 { + char data[8]; + }; #pragma pack(pop) static_assert(sizeof(hash) == HASH_SIZE, "Invalid structure size"); + static_assert(sizeof(hash8) == 8, "Invalid structure size"); /* Cryptonight hash functions @@ -74,3 +78,4 @@ namespace crypto { } CRYPTO_MAKE_HASHABLE(hash) +CRYPTO_MAKE_COMPARABLE(hash8) 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 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 std::ostream &print256(std::ostream &o, const T &v) { return o << "<" << epee::string_tools::pod_to_hex(v) << ">"; } +template +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 a79c3cdd3..af8e703bf 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -334,26 +334,43 @@ namespace cryptonote return true; } //--------------------------------------------------------------- - void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id, bool encrypted) + void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id) { extra_nonce.clear(); - extra_nonce.push_back(encrypted ? TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID : TX_EXTRA_NONCE_PAYMENT_ID); + extra_nonce.push_back(TX_EXTRA_NONCE_PAYMENT_ID); const uint8_t* payment_id_ptr = reinterpret_cast(&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, bool &encrypted) + 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(&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()) return false; - if(TX_EXTRA_NONCE_PAYMENT_ID != extra_nonce[0] && TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID != extra_nonce[0]) + if(TX_EXTRA_NONCE_PAYMENT_ID != extra_nonce[0]) return false; payment_id = *reinterpret_cast(extra_nonce.data() + 1); - encrypted = TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID == extra_nonce[0]; return true; } //--------------------------------------------------------------- - crypto::public_key get_destination_view_key_pub(const std::vector &destinations) + 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(extra_nonce.data() + 1); + return true; + } + //--------------------------------------------------------------- + crypto::public_key get_destination_view_key_pub(const std::vector &destinations, const account_keys &sender_keys) { if (destinations.empty()) return null_pkey; @@ -367,7 +384,7 @@ namespace cryptonote return destinations[0].addr.m_view_public_key; } //--------------------------------------------------------------- - bool encrypt_payment_id(crypto::hash &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_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; @@ -380,12 +397,12 @@ namespace cryptonote data[32] = ENCRYPTED_PAYMENT_ID_TAIL; cn_fast_hash(data, 33, hash); - for (size_t b = 0; b < 32; ++b) + for (size_t b = 0; b < 8; ++b) payment_id.data[b] ^= hash.data[b]; return true; } - bool decrypt_payment_id(crypto::hash &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) { // Encryption and decryption are the same operation (xor with a key) return encrypt_payment_id(payment_id, public_key, secret_key); @@ -411,13 +428,12 @@ namespace cryptonote tx_extra_nonce extra_nonce; if (find_tx_extra_field_by_type(tx_extra_fields, extra_nonce)) { - crypto::hash payment_id = null_hash; - bool encrypted; - if (get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id, encrypted) && encrypted) + 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); + 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"); @@ -431,7 +447,7 @@ namespace cryptonote } std::string extra_nonce; - set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id, true); + 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)) { diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h index 69baa20cf..319205368 100644 --- a/src/cryptonote_core/cryptonote_format_utils.h +++ b/src/cryptonote_core/cryptonote_format_utils.h @@ -45,8 +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::hash &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key); - bool decrypt_payment_id(crypto::hash &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key); + 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 { @@ -88,8 +88,10 @@ namespace cryptonote 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& tx_extra, const blobdata& extra_nonce); bool remove_extra_nonce_tx_extra(std::vector& tx_extra); - void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id, bool encrypted); - bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id, bool &encrypted); + 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& outs, uint64_t& money_transfered); bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, uint64_t& money_transfered); diff --git a/src/serialization/crypto.h b/src/serialization/crypto.h index f18e85b12..575697c06 100644 --- a/src/serialization/crypto.h +++ b/src/serialization/crypto.h @@ -79,12 +79,14 @@ bool do_serialize(Archive &ar, std::vector &v) BLOB_SERIALIZER(crypto::chacha8_iv); BLOB_SERIALIZER(crypto::hash); +BLOB_SERIALIZER(crypto::hash8); BLOB_SERIALIZER(crypto::public_key); BLOB_SERIALIZER(crypto::secret_key); BLOB_SERIALIZER(crypto::key_derivation); BLOB_SERIALIZER(crypto::key_image); BLOB_SERIALIZER(crypto::signature); VARIANT_TAG(debug_archive, crypto::hash, "hash"); +VARIANT_TAG(debug_archive, crypto::hash8, "hash8"); VARIANT_TAG(debug_archive, crypto::public_key, "public_key"); VARIANT_TAG(debug_archive, crypto::secret_key, "secret_key"); VARIANT_TAG(debug_archive, crypto::key_derivation, "key_derivation"); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 9c2396029..01d052ce4 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -601,7 +601,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) // parse address cryptonote::account_public_address address; bool has_payment_id; - crypto::hash new_payment_id; + crypto::hash8 new_payment_id; if(!get_account_integrated_address_from_str(address, has_payment_id, new_payment_id, testnet, parts[0])) { fail_msg_writer() << tr("Failed to parse address"); @@ -1288,36 +1288,45 @@ bool simple_wallet::transfer_main(bool new_algorithm, const std::vector extra; bool payment_id_seen = false; - bool encrypt_payment_id = false; if (1 == local_args.size() % 2) { std::string payment_id_str = local_args.back(); local_args.pop_back(); crypto::hash payment_id; - bool r = tools::wallet2::parse_payment_id(payment_id_str, payment_id); + bool r = tools::wallet2::parse_long_payment_id(payment_id_str, payment_id); if(r) { std::string extra_nonce; - set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id, false); + set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id); r = add_extra_nonce_to_tx_extra(extra, extra_nonce); } + else + { + crypto::hash8 payment_id8; + r = tools::wallet2::parse_short_payment_id(payment_id_str, payment_id8); + if(r) + { + std::string extra_nonce; + set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id8); + r = add_extra_nonce_to_tx_extra(extra, extra_nonce); + } + } if(!r) { - fail_msg_writer() << tr("payment id has invalid format, expected 64-character string: ") << payment_id_str; + fail_msg_writer() << tr("payment id has invalid format, expected 16 or 64 character string: ") << payment_id_str; return true; } payment_id_seen = true; } vector dsts; - crypto::hash payment_id = null_hash; for (size_t i = 0; i < local_args.size(); i += 2) { cryptonote::tx_destination_entry de; bool has_payment_id; - crypto::hash new_payment_id; + crypto::hash8 new_payment_id; if(!get_account_integrated_address_from_str(de.addr, has_payment_id, new_payment_id, m_wallet->testnet(), local_args[i])) { // if treating as an address fails, try as url @@ -1377,29 +1386,22 @@ bool simple_wallet::transfer_main(bool new_algorithm, const std::vector &args/* = std:: //---------------------------------------------------------------------------------------------------- bool simple_wallet::print_integrated_address(const std::vector &args/* = std::vector()*/) { - crypto::hash payment_id; + crypto::hash8 payment_id; if (args.size() > 1) { fail_msg_writer() << tr("integrated_address only takes one or zero arguments"); @@ -1710,19 +1712,19 @@ bool simple_wallet::print_integrated_address(const std::vector &arg } if (args.size() == 0) { - crypto::generate_random_bytes(32, payment_id.data); + crypto::generate_random_bytes(8, payment_id.data); success_msg_writer() << tr("Random payment ID: ") << payment_id; success_msg_writer() << tr("Matching integrated address: ") << m_wallet->get_account().get_public_integrated_address_str(payment_id, m_wallet->testnet()); return true; } - if(tools::wallet2::parse_payment_id(args.back(), payment_id)) + if(tools::wallet2::parse_short_payment_id(args.back(), payment_id)) { success_msg_writer() << m_wallet->get_account().get_public_integrated_address_str(payment_id, m_wallet->testnet()); return true; } else { bool has_payment_id; - crypto::hash payment_id; + crypto::hash8 payment_id; account_public_address addr; if(get_account_integrated_address_from_str(addr, has_payment_id, payment_id, m_wallet->testnet(), args.back())) { diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 12db73423..3d3f1e4de 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -237,20 +237,24 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_ crypto::hash payment_id = null_hash; if (find_tx_extra_field_by_type(tx_extra_fields, extra_nonce)) { - bool encrypted; - if(get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id, encrypted) && encrypted) + crypto::hash8 payment_id8 = null_hash8; + if(get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8)) { // We got a payment ID to go with this tx - LOG_PRINT_L2("Found encrypted payment ID: " << payment_id); + LOG_PRINT_L2("Found encrypted payment ID: " << payment_id8); if (tx_pub_key != null_pkey) { - if (!decrypt_payment_id(payment_id, tx_pub_key, m_account.get_keys().m_view_secret_key)) + if (!decrypt_payment_id(payment_id8, tx_pub_key, m_account.get_keys().m_view_secret_key)) { - LOG_PRINT_L0("Failed to decrypt payment ID: " << payment_id); + LOG_PRINT_L0("Failed to decrypt payment ID: " << payment_id8); } else { - LOG_PRINT_L2("Decrypted payment ID: " << payment_id); + LOG_PRINT_L2("Decrypted payment ID: " << payment_id8); + // put the 64 bit decrypted payment id in the first 8 bytes + memcpy(payment_id.data, payment_id8.data, 8); + // rest is already 0, but guard against code changes above + memset(payment_id.data + 8, 0, 24); } } else @@ -258,6 +262,10 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_ LOG_PRINT_L1("No public key found in tx, unable to decrypt payment id"); } } + else if (get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id)) + { + LOG_PRINT_L2("Found unencrypted payment ID: " << payment_id); + } } uint64_t received = (tx_money_spent_in_ins < tx_money_got_in_outs) ? tx_money_got_in_outs - tx_money_spent_in_ins : 0; if (0 < received) @@ -783,7 +791,7 @@ bool wallet2::wallet_valid_path_format(const std::string& file_path) return !file_path.empty(); } //---------------------------------------------------------------------------------------------------- -bool wallet2::parse_payment_id(const std::string& payment_id_str, crypto::hash& payment_id) +bool wallet2::parse_long_payment_id(const std::string& payment_id_str, crypto::hash& payment_id) { cryptonote::blobdata payment_id_data; if(!epee::string_tools::parse_hexstr_to_binbuff(payment_id_str, payment_id_data)) @@ -796,6 +804,33 @@ bool wallet2::parse_payment_id(const std::string& payment_id_str, crypto::hash& return true; } //---------------------------------------------------------------------------------------------------- +bool wallet2::parse_short_payment_id(const std::string& payment_id_str, crypto::hash8& payment_id) +{ + cryptonote::blobdata payment_id_data; + if(!epee::string_tools::parse_hexstr_to_binbuff(payment_id_str, payment_id_data)) + return false; + + if(sizeof(crypto::hash8) != payment_id_data.size()) + return false; + + payment_id = *reinterpret_cast(payment_id_data.data()); + return true; +} +//---------------------------------------------------------------------------------------------------- +bool wallet2::parse_payment_id(const std::string& payment_id_str, crypto::hash& payment_id) +{ + if (parse_long_payment_id(payment_id_str, payment_id)) + return true; + crypto::hash8 payment_id8; + if (parse_short_payment_id(payment_id_str, payment_id8)) + { + memcpy(payment_id.data, payment_id8.data, 8); + memset(payment_id.data + 8, 0, 24); + return true; + } + return false; +} +//---------------------------------------------------------------------------------------------------- bool wallet2::prepare_file_names(const std::string& file_path) { do_prepare_file_names(file_path, m_keys_file, m_wallet_file); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 93119cd0b..eee6aa58c 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -266,6 +266,8 @@ namespace tools */ static bool wallet_valid_path_format(const std::string& file_path); + static bool parse_long_payment_id(const std::string& payment_id_str, crypto::hash& payment_id); + static bool parse_short_payment_id(const std::string& payment_id_str, crypto::hash8& payment_id); static bool parse_payment_id(const std::string& payment_id_str, crypto::hash& payment_id); static std::vector addresses_from_url(const std::string& url, bool& dnssec_valid); diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 4797f76a2..7dfd64eef 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -117,14 +117,15 @@ namespace tools } //------------------------------------------------------------------------------------------------------------------------------ - bool wallet_rpc_server::validate_transfer(const std::list destinations, std::string payment_id, bool encrypt_payment_id, std::vector& dsts, std::vector& extra, epee::json_rpc::error& er) + bool wallet_rpc_server::validate_transfer(const std::list destinations, std::string payment_id, std::vector& dsts, std::vector& extra, epee::json_rpc::error& er) { - crypto::hash integrated_payment_id = cryptonote::null_hash; + crypto::hash8 integrated_payment_id = cryptonote::null_hash8; + std::string extra_nonce; for (auto it = destinations.begin(); it != destinations.end(); it++) { cryptonote::tx_destination_entry de; bool has_payment_id; - crypto::hash new_payment_id; + crypto::hash8 new_payment_id; if(!get_account_integrated_address_from_str(de.addr, has_payment_id, new_payment_id, m_wallet.testnet(), it->address)) { er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS; @@ -136,17 +137,15 @@ namespace tools if (has_payment_id) { - if (!payment_id.empty() || integrated_payment_id != cryptonote::null_hash) + if (!payment_id.empty() || integrated_payment_id != cryptonote::null_hash8) { er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID; er.message = "A single payment id is allowed per transaction"; return false; } integrated_payment_id = new_payment_id; + cryptonote::set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, integrated_payment_id); } - - // integrated addresses imply encrypted payment id - encrypt_payment_id = true; } if (!payment_id.empty()) @@ -155,17 +154,23 @@ namespace tools /* Just to clarify */ const std::string& payment_id_str = payment_id; - crypto::hash payment_id; + crypto::hash long_payment_id; + crypto::hash8 short_payment_id; + /* Parse payment ID */ - if (!wallet2::parse_payment_id(payment_id_str, payment_id)) { + if (wallet2::parse_long_payment_id(payment_id_str, long_payment_id)) { + cryptonote::set_payment_id_to_tx_extra_nonce(extra_nonce, long_payment_id); + } + /* or short payment ID */ + else if (!wallet2::parse_short_payment_id(payment_id_str, short_payment_id)) { + cryptonote::set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, short_payment_id); + } + else { er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID; - er.message = "Payment id has invalid format: \"" + payment_id_str + "\", expected 64-character string"; + er.message = "Payment id has invalid format: \"" + payment_id_str + "\", expected 16 or 64 character string"; return false; } - std::string extra_nonce; - cryptonote::set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id, encrypt_payment_id); - /* Append Payment ID data into extra */ if (!cryptonote::add_extra_nonce_to_tx_extra(extra, extra_nonce)) { er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID; @@ -192,7 +197,7 @@ namespace tools } // validate the transfer requested and populate dsts & extra - if (!validate_transfer(req.destinations, req.payment_id, req.encrypt_payment_id, dsts, extra, er)) + if (!validate_transfer(req.destinations, req.payment_id, dsts, extra, er)) { return false; } @@ -250,7 +255,7 @@ namespace tools } // validate the transfer requested and populate dsts & extra; RPC_TRANSFER::request and RPC_TRANSFER_SPLIT::request are identical types. - if (!validate_transfer(req.destinations, req.payment_id, req.encrypt_payment_id, dsts, extra, er)) + if (!validate_transfer(req.destinations, req.payment_id, dsts, extra, er)) { return false; } @@ -342,14 +347,14 @@ namespace tools { try { - crypto::hash payment_id; + crypto::hash8 payment_id; if (req.payment_id.empty()) { - crypto::generate_random_bytes(32, payment_id.data); + crypto::generate_random_bytes(8, payment_id.data); } else { - if (!tools::wallet2::parse_payment_id(req.payment_id,payment_id)) + if (!tools::wallet2::parse_short_payment_id(req.payment_id,payment_id)) { er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID; er.message = "Invalid payment ID"; @@ -374,7 +379,7 @@ namespace tools try { cryptonote::account_public_address address; - crypto::hash payment_id; + crypto::hash8 payment_id; bool has_payment_id; if(!get_account_integrated_address_from_str(address, has_payment_id, payment_id, m_wallet.testnet(), req.integrated_address)) @@ -488,6 +493,7 @@ namespace tools for (auto & payment_id_str : req.payment_ids) { crypto::hash payment_id; + crypto::hash8 payment_id8; cryptonote::blobdata payment_id_blob; // TODO - should the whole thing fail because of one bad id? @@ -499,15 +505,23 @@ namespace tools return false; } - if(sizeof(payment_id) != payment_id_blob.size()) + if(sizeof(payment_id) == payment_id_blob.size()) + { + payment_id = *reinterpret_cast(payment_id_blob.data()); + } + else if(sizeof(payment_id8) == payment_id_blob.size()) + { + payment_id8 = *reinterpret_cast(payment_id_blob.data()); + memcpy(payment_id.data, payment_id8.data, 8); + memset(payment_id.data + 8, 0, 24); + } + else { er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID; er.message = "Payment ID has invalid size: " + payment_id_str; return false; } - payment_id = *reinterpret_cast(payment_id_blob.data()); - std::list payment_list; m_wallet.get_payments(payment_id, payment_list, req.min_block_height); diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h index fbe0964d1..73411a98d 100644 --- a/src/wallet/wallet_rpc_server.h +++ b/src/wallet/wallet_rpc_server.h @@ -79,7 +79,7 @@ namespace tools //json_rpc bool on_getbalance(const wallet_rpc::COMMAND_RPC_GET_BALANCE::request& req, wallet_rpc::COMMAND_RPC_GET_BALANCE::response& res, epee::json_rpc::error& er); bool on_getaddress(const wallet_rpc::COMMAND_RPC_GET_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_GET_ADDRESS::response& res, epee::json_rpc::error& er); - bool validate_transfer(const std::list destinations, const std::string payment_id, bool encrypt_payment_id, std::vector& dsts, std::vector& extra, epee::json_rpc::error& er); + bool validate_transfer(const std::list destinations, const std::string payment_id, std::vector& dsts, std::vector& extra, epee::json_rpc::error& er); bool on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er); bool on_transfer_split(const wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::request& req, wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::response& res, epee::json_rpc::error& er); bool on_sweep_dust(const wallet_rpc::COMMAND_RPC_SWEEP_DUST::request& req, wallet_rpc::COMMAND_RPC_SWEEP_DUST::response& res, epee::json_rpc::error& er); diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index 8897397af..7786ab009 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -97,7 +97,6 @@ namespace wallet_rpc uint64_t mixin; uint64_t unlock_time; std::string payment_id; - bool encrypt_payment_id; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(destinations) @@ -105,7 +104,6 @@ namespace wallet_rpc KV_SERIALIZE(mixin) KV_SERIALIZE(unlock_time) KV_SERIALIZE(payment_id) - KV_SERIALIZE(encrypt_payment_id) END_KV_SERIALIZE_MAP() }; @@ -129,7 +127,6 @@ namespace wallet_rpc uint64_t unlock_time; std::string payment_id; bool new_algorithm; - bool encrypt_payment_id; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(destinations) @@ -138,7 +135,6 @@ namespace wallet_rpc KV_SERIALIZE(unlock_time) KV_SERIALIZE(payment_id) KV_SERIALIZE(new_algorithm) - KV_SERIALIZE(encrypt_payment_id) END_KV_SERIALIZE_MAP() };