aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_basic
diff options
context:
space:
mode:
authormoneromooo-monero <moneromooo-monero@users.noreply.github.com>2018-08-03 10:21:08 +0000
committermoneromooo-monero <moneromooo-monero@users.noreply.github.com>2018-10-07 11:13:22 +0000
commit9907ea0694ecf025258fd1b28e3dcc8c2c1b54d0 (patch)
tree84a36096707f4ac99bb04c44975eb26aa4cd27c8 /src/cryptonote_basic
parentMerge pull request #4223 (diff)
downloadmonero-9907ea0694ecf025258fd1b28e3dcc8c2c1b54d0.tar.xz
cryptonote: sort tx_extra fields
This removes some small amount of fingerprinting entropy. There is no consensus rule to require this since this field is technically free form, and a transaction is free to have custom data in it.
Diffstat (limited to 'src/cryptonote_basic')
-rw-r--r--src/cryptonote_basic/cryptonote_basic.h1
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.cpp85
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.h2
3 files changed, 87 insertions, 1 deletions
diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h
index d4558ef7b..b0eabb0aa 100644
--- a/src/cryptonote_basic/cryptonote_basic.h
+++ b/src/cryptonote_basic/cryptonote_basic.h
@@ -47,7 +47,6 @@
#include "crypto/crypto.h"
#include "crypto/hash.h"
#include "misc_language.h"
-#include "tx_extra.h"
#include "ringct/rctTypes.h"
#include "device/device.hpp"
diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp
index 428be1c9c..0231a032e 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.cpp
+++ b/src/cryptonote_basic/cryptonote_format_utils.cpp
@@ -376,6 +376,91 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
+ template<typename T>
+ static bool pick(binary_archive<true> &ar, std::vector<tx_extra_field> &fields, uint8_t tag)
+ {
+ std::vector<tx_extra_field>::iterator it;
+ while ((it = std::find_if(fields.begin(), fields.end(), [](const tx_extra_field &f) { return f.type() == typeid(T); })) != fields.end())
+ {
+ bool r = ::do_serialize(ar, tag);
+ CHECK_AND_NO_ASSERT_MES_L1(r, false, "failed to serialize tx extra field");
+ r = ::do_serialize(ar, boost::get<T>(*it));
+ CHECK_AND_NO_ASSERT_MES_L1(r, false, "failed to serialize tx extra field");
+ fields.erase(it);
+ }
+ return true;
+ }
+ //---------------------------------------------------------------
+ bool sort_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<uint8_t> &sorted_tx_extra, bool allow_partial)
+ {
+ std::vector<tx_extra_field> tx_extra_fields;
+
+ if(tx_extra.empty())
+ {
+ sorted_tx_extra.clear();
+ return true;
+ }
+
+ std::string extra_str(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size());
+ std::istringstream iss(extra_str);
+ binary_archive<false> ar(iss);
+
+ bool eof = false;
+ size_t processed = 0;
+ while (!eof)
+ {
+ tx_extra_field field;
+ bool r = ::do_serialize(ar, field);
+ if (!r)
+ {
+ MWARNING("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 (!allow_partial)
+ return false;
+ break;
+ }
+ tx_extra_fields.push_back(field);
+ processed = iss.tellg();
+
+ std::ios_base::iostate state = iss.rdstate();
+ eof = (EOF == iss.peek());
+ iss.clear(state);
+ }
+ if (!::serialization::check_stream_state(ar))
+ {
+ MWARNING("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 (!allow_partial)
+ return false;
+ }
+ MTRACE("Sorted " << processed << "/" << tx_extra.size());
+
+ std::ostringstream oss;
+ binary_archive<true> nar(oss);
+
+ // sort by:
+ if (!pick<tx_extra_pub_key>(nar, tx_extra_fields, TX_EXTRA_TAG_PUBKEY)) return false;
+ if (!pick<tx_extra_additional_pub_keys>(nar, tx_extra_fields, TX_EXTRA_TAG_ADDITIONAL_PUBKEYS)) return false;
+ if (!pick<tx_extra_nonce>(nar, tx_extra_fields, TX_EXTRA_NONCE)) return false;
+ if (!pick<tx_extra_merge_mining_tag>(nar, tx_extra_fields, TX_EXTRA_MERGE_MINING_TAG)) return false;
+ if (!pick<tx_extra_mysterious_minergate>(nar, tx_extra_fields, TX_EXTRA_MYSTERIOUS_MINERGATE_TAG)) return false;
+ if (!pick<tx_extra_padding>(nar, tx_extra_fields, TX_EXTRA_TAG_PADDING)) return false;
+
+ // if not empty, someone added a new type and did not add a case above
+ if (!tx_extra_fields.empty())
+ {
+ MERROR("tx_extra_fields not empty after sorting, someone forgot to add a case above");
+ return false;
+ }
+
+ std::string oss_str = oss.str();
+ if (allow_partial && processed < tx_extra.size())
+ {
+ MDEBUG("Appending unparsed data");
+ oss_str += std::string((const char*)tx_extra.data() + processed, tx_extra.size() - processed);
+ }
+ sorted_tx_extra = std::vector<uint8_t>(oss_str.begin(), oss_str.end());
+ return true;
+ }
+ //---------------------------------------------------------------
crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra, size_t pk_index)
{
std::vector<tx_extra_field> tx_extra_fields;
diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h
index 8a5296d5b..b40db4668 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.h
+++ b/src/cryptonote_basic/cryptonote_format_utils.h
@@ -31,6 +31,7 @@
#pragma once
#include "blobdatatype.h"
#include "cryptonote_basic_impl.h"
+#include "tx_extra.h"
#include "account.h"
#include "subaddress_index.h"
#include "include_base_utils.h"
@@ -64,6 +65,7 @@ namespace cryptonote
}
bool parse_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<tx_extra_field>& tx_extra_fields);
+ bool sort_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<uint8_t> &sorted_tx_extra, bool allow_partial = false);
crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra, size_t pk_index = 0);
crypto::public_key get_tx_pub_key_from_extra(const transaction_prefix& tx, size_t pk_index = 0);
crypto::public_key get_tx_pub_key_from_extra(const transaction& tx, size_t pk_index = 0);