Add carrot tx proof support (get_tx_proof and check_tx_proof)

This commit is contained in:
auruya
2025-11-17 19:58:40 +03:00
parent 1503ec6629
commit fcaf640bcb

View File

@@ -13220,6 +13220,58 @@ std::string wallet2::get_tx_proof(const cryptonote::transaction &tx, const crypt
std::vector<crypto::public_key> shared_secret;
std::vector<crypto::signature> sig;
std::string sig_str;
// Carrot proof
if (address.m_is_carrot)
{
std::vector<crypto::key_derivation> derivations;
if (is_out)
{
// Sender has tx_key
const size_t num_derivs = 1 + additional_tx_keys.size();
derivations.resize(num_derivs);
// Main derivation
mx25519_pubkey s_sender_receiver_unctx;
bool success = carrot::make_carrot_uncontextualized_shared_key_sender(
tx_key,
address.m_view_public_key,
s_sender_receiver_unctx);
THROW_WALLET_EXCEPTION_IF(!success, error::wallet_internal_error,
"Failed to generate X25519 key derivation for carrot proof (main)");
derivations[0] = carrot::raw_byte_convert<crypto::key_derivation>(s_sender_receiver_unctx);
// Additional derivations
for (size_t i = 0; i < additional_tx_keys.size(); ++i)
{
mx25519_pubkey additional_s_sender_receiver_unctx;
success = carrot::make_carrot_uncontextualized_shared_key_sender(
additional_tx_keys[i],
address.m_view_public_key,
additional_s_sender_receiver_unctx);
THROW_WALLET_EXCEPTION_IF(!success, error::wallet_internal_error,
"Failed to generate X25519 key derivation for carrot proof (additional)");
derivations[i + 1] = carrot::raw_byte_convert<crypto::key_derivation>(additional_s_sender_receiver_unctx);
}
sig_str = std::string("CarrotOutProofV1");
}
else
{
// view key can be used
sig_str = std::string("CarrotInProofV1");
}
// derivation encoding
for (size_t i = 0; i < derivations.size(); ++i)
sig_str += tools::base58::encode(std::string((const char *)&derivations[i], sizeof(crypto::key_derivation)));
return sig_str;
}
// Legacy proof
if (is_out)
{
const size_t num_sigs = 1 + additional_tx_keys.size();
@@ -13372,6 +13424,44 @@ bool wallet2::check_tx_proof(const crypto::hash &txid, const cryptonote::account
bool wallet2::check_tx_proof(const cryptonote::transaction &tx, const cryptonote::account_public_address &address, bool is_subaddress, const std::string &message, const std::string &sig_str, uint64_t &received) const
{
//
if (sig_str.substr(0, 6) == "Carrot")
{
THROW_WALLET_EXCEPTION_IF(!address.m_is_carrot, error::wallet_internal_error,
"Carrot proof provided but address is not a carrot address");
const bool is_out = sig_str.substr(6, 3) == "Out";
std::vector<crypto::key_derivation> derivations(1);
const std::string header = is_out ? "CarrotOutProofV1" : "CarrotInProofV1";
const size_t header_len = header.size();
THROW_WALLET_EXCEPTION_IF(sig_str.size() < header_len || sig_str.substr(0, header_len) != header, error::wallet_internal_error,
"Signature header check error");
const size_t deriv_len = tools::base58::encode(std::string((const char *)&derivations[0], sizeof(crypto::key_derivation))).size();
const size_t num_derivs = (sig_str.size() - header_len) / deriv_len;
derivations.resize(num_derivs);
// Decode all derivations from base58
for (size_t i = 0; i < num_derivs; ++i)
{
std::string deriv_decoded;
const size_t offset = header_len + i * deriv_len;
THROW_WALLET_EXCEPTION_IF(!tools::base58::decode(sig_str.substr(offset, deriv_len), deriv_decoded), error::wallet_internal_error,
"Derivation decoding error");
THROW_WALLET_EXCEPTION_IF(sizeof(crypto::key_derivation) != deriv_decoded.size(), error::wallet_internal_error,
"Derivation decoding error");
memcpy(&derivations[i], deriv_decoded.data(), sizeof(crypto::key_derivation));
}
std::vector<crypto::key_derivation> additional_derivations(derivations.begin() + 1, derivations.end());
check_tx_key_helper(tx, derivations[0], additional_derivations, address, received);
return true;
}
// Legacy proof handling
THROW_WALLET_EXCEPTION_IF(address.m_is_carrot, error::wallet_internal_error,
"Legacy proof provided but address is a carrot address");
// InProofV1, InProofV2, OutProofV1, OutProofV2
const bool is_out = sig_str.substr(0, 3) == "Out";
const std::string header = is_out ? sig_str.substr(0,10) : sig_str.substr(0,9);