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() };