You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmonero/src/UniversalIdentifier.hpp

333 lines
8.3 KiB

#pragma once
#include "om_log.h"
#include "tools.h"
#include "MicroCore.h"
#include <tuple>
#include <utility>
namespace xmreg
{
using namespace std;
class AbstractIdentifier
{
public:
virtual void identify(transaction const& tx,
public_key const& tx_pub_key,
vector<public_key> const& additional_tx_pub_keys
= vector<public_key>{}) = 0;
};
class BaseIdentifier : public AbstractIdentifier
{
public:
BaseIdentifier(
address_parse_info const* _address,
secret_key const* _viewkey)
: address_info {_address}, viewkey {_viewkey}
{}
virtual void identify(transaction const& tx,
public_key const& tx_pub_key,
vector<public_key> const& additional_tx_pub_keys
= vector<public_key>{}) = 0;
inline auto get_address() const {return address_info;}
inline auto get_viewkey() const {return viewkey;}
inline auto get_total() const {return total_xmr;}
virtual ~BaseIdentifier() = default;
protected:
address_parse_info const* address_info {nullptr};
secret_key const* viewkey {nullptr};
uint64_t total_xmr {0};
};
/**
* @brief The Output class identifies our
* outputs in a given tx
*/
class Output : public BaseIdentifier
{
public:
Output(address_parse_info const* _address,
secret_key const* _viewkey)
: BaseIdentifier(_address, _viewkey)
{}
void identify(transaction const& tx,
public_key const& tx_pub_key,
vector<public_key> const& additional_tx_pub_keys
= vector<public_key>{}) override;
inline auto get() const
{
return identified_outputs;
}
struct info
{
public_key pub_key;
uint64_t amount;
uint64_t idx_in_tx;
key_derivation derivation;
rct::key rtc_outpk;
rct::key rtc_mask;
rct::key rtc_amount;
friend std::ostream& operator<<(std::ostream& os, info const& _info);
};
protected:
uint64_t total_received {0};
vector<info> identified_outputs;
};
/**
* @brief The Input class identifies our possible
* inputs (key images) in a given tx
*/
class Input : public BaseIdentifier
{
public:
//output_pubk , amount
using known_outputs_t = unordered_map<public_key, uint64_t>;
Input(address_parse_info const* _a,
secret_key const* _viewkey,
known_outputs_t const* _known_outputs,
MicroCore* _mcore)
: BaseIdentifier(_a, _viewkey),
known_outputs {_known_outputs},
mcore {_mcore}
{}
void identify(transaction const& tx,
public_key const& tx_pub_key,
vector<public_key> const& additional_tx_pub_keys
= vector<public_key>{}) override;
inline auto get() const
{
return identified_inputs;
}
struct info
{
key_image key_img;
uint64_t amount;
public_key out_pub_key;
friend std::ostream& operator<<(std::ostream& os, info const& _info);
};
protected:
secret_key const* viewkey {nullptr};
known_outputs_t const* known_outputs {nullptr};
MicroCore* mcore {nullptr};
vector<info> identified_inputs;
};
/**
* Spendkey is optional. But if we have it,
* we can for sure determine which key images
* are ours or not. This is especially useful
* in unit testing, since we can compare wether
* guessed key images do contain all our key images
*/
class RealInput : public Input
{
public:
RealInput(address_parse_info const* _a,
secret_key const* _viewkey,
secret_key const* _spendkey,
MicroCore* _mcore)
: Input(_a, _viewkey, nullptr, _mcore),
spendkey {_spendkey}
{}
void identify(transaction const& tx,
public_key const& tx_pub_key,
vector<public_key> const& additional_tx_pub_keys
= vector<public_key>{}) override;
protected:
secret_key const* spendkey {nullptr};
};
template <typename HashT>
class PaymentID : public BaseIdentifier
{
public:
PaymentID(address_parse_info const* _address,
secret_key const* _viewkey)
: BaseIdentifier(_address, _viewkey)
{}
void identify(transaction const& tx,
public_key const& tx_pub_key,
vector<public_key> const& additional_tx_pub_keys
= vector<public_key>{}) override
{
cout << "PaymentID decryption: "
+ pod_to_hex(payment_id) << endl;
// get payment id. by default we are intrested
// in short ids from integrated addresses
auto payment_id_tuple = xmreg::get_payment_id(tx);
payment_id = std::get<HashT>(payment_id_tuple);
// if no payment_id found, return
if (payment_id == null_hash)
return;
// decrypt integrated payment id. if its legacy payment id
// nothing will happen.
if (!decrypt(payment_id, tx_pub_key))
{
throw std::runtime_error("Cant decrypt pay_id: "
+ pod_to_hex(payment_id));
}
}
inline bool
decrypt(crypto::hash& p_id,
public_key const& tx_pub_key) const
{
// don't need to do anything for legacy payment ids
return true;
}
inline bool
decrypt(crypto::hash8& p_id,
public_key const& tx_pub_key) const
{
// overload for short payment id,
// the we are going to decrypt
return xmreg::encrypt_payment_id(
p_id, tx_pub_key, *get_viewkey());
}
inline auto get() const {return payment_id;}
private:
HashT payment_id {};
HashT null_hash {};
};
using LegacyPaymentID = PaymentID<crypto::hash>;
using IntegratedPaymentID = PaymentID<crypto::hash8>;
template<typename... T>
class ModularIdentifier
{
public:
tuple<unique_ptr<T>...> identifiers;
ModularIdentifier(transaction const& _tx,
unique_ptr<T>... args)
: identifiers {move(args)...},
tx {_tx}
{
// having tx public key is very common for all identifiers
// so we can get it here, instead of just obtaining it
// for each identifier seprately
tx_pub_key = get_tx_pub_key_from_received_outs(tx);
// multi-output txs can have some additional public keys
// in the extra field. So we also get them, just in case
additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(tx);
}
void identify()
{
auto b = {(std::get<unique_ptr<T>>(
identifiers)->identify(
tx, tx_pub_key, additional_tx_pub_keys),
true)...};
(void) b;
}
// overload to get value from tuple by type
template <typename U>
auto* const get()
{
return std::get<unique_ptr<U>>(identifiers).get();
}
// overload to get value from tuple by number
template <size_t No>
auto* const get()
{
return std::get<No>(identifiers).get();
}
inline auto get_tx_pub_key() const {return tx_pub_key;}
private:
transaction const& tx;
public_key tx_pub_key;
vector<public_key> additional_tx_pub_keys;
};
/**
* A helper function to create ModularIdentifier object
*/
template<typename... T>
auto make_identifier(transaction const& tx, T&&... identifiers)
{
return ModularIdentifier<typename T::element_type...>(
tx, std::forward<T>(identifiers)...);
}
template <typename T>
auto
calc_total_xmr(T&& infos)
{
uint64_t total_xmr {0};
for (auto const& info: infos)
total_xmr += info.amount;
return total_xmr;
}
inline std::ostream&
operator<<(std::ostream& os, xmreg::Output::info const& _info)
{
return os << _info.idx_in_tx << ", "
<< pod_to_hex(_info.pub_key) << ", "
<< _info.amount;
}
inline std::ostream&
operator<<(std::ostream& os, xmreg::Input::info const& _info)
{
return os << pod_to_hex(_info.key_img) << ", "
<< pod_to_hex(_info.out_pub_key) << ", "
<< _info.amount;
}
}