add get carrot tx proof support for sender
This commit is contained in:
@@ -41,6 +41,7 @@
|
||||
#include "common/varint.h"
|
||||
#include "warnings.h"
|
||||
#include "crypto.h"
|
||||
#include "mx25519.h"
|
||||
#include "hash.h"
|
||||
|
||||
#include "cryptonote_config.h"
|
||||
@@ -504,6 +505,95 @@ namespace crypto {
|
||||
memwipe(&k, sizeof(k));
|
||||
}
|
||||
|
||||
void crypto_ops::generate_carrot_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const secret_key &r, signature &sig) {
|
||||
// sanity check
|
||||
ge_p3 R_p3;
|
||||
ge_p3 A_p3;
|
||||
ge_p3 B_p3;
|
||||
if (ge_frombytes_vartime(&R_p3, &R) != 0) throw std::runtime_error("tx pubkey is invalid");
|
||||
if (ge_frombytes_vartime(&A_p3, &A) != 0) throw std::runtime_error("recipient view pubkey is invalid");
|
||||
if (B && ge_frombytes_vartime(&B_p3, &*B) != 0) throw std::runtime_error("recipient spend pubkey is invalid");
|
||||
#if !defined(NDEBUG)
|
||||
{
|
||||
assert(sc_check(&r) == 0);
|
||||
// check R == r*G or R == r*B
|
||||
public_key dbg_R;
|
||||
if (B)
|
||||
{
|
||||
ge_p2 dbg_R_p2;
|
||||
ge_scalarmult(&dbg_R_p2, &r, &B_p3);
|
||||
ge_tobytes(&dbg_R, &dbg_R_p2);
|
||||
}
|
||||
else
|
||||
{
|
||||
ge_p3 dbg_R_p3;
|
||||
ge_scalarmult_base(&dbg_R_p3, &r);
|
||||
ge_p3_tobytes(&dbg_R, &dbg_R_p3);
|
||||
}
|
||||
assert(R == dbg_R);
|
||||
|
||||
// check D == r*A // move here to wallet2.cpp later
|
||||
ge_p2 dbg_D_p2;
|
||||
ge_scalarmult(&dbg_D_p2, &r, &A_p3);
|
||||
public_key dbg_D;
|
||||
ge_tobytes(&dbg_D, &dbg_D_p2);
|
||||
|
||||
// convert D to x25519 format for comparison
|
||||
ge_p3 D_p3;
|
||||
ge_frombytes_vartime(&D_p3, &dbg_D);
|
||||
mx25519_pubkey D_x25519;
|
||||
ge_p3_to_x25519(D_x25519.data, &D_p3);
|
||||
assert(memcmp(D.data, D_x25519.data, 32) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// pick random k
|
||||
ec_scalar k;
|
||||
random_scalar(k);
|
||||
|
||||
// if B is not present
|
||||
static const ec_point zero = {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }};
|
||||
|
||||
s_comm_2 buf;
|
||||
buf.msg = prefix_hash;
|
||||
buf.D = D;
|
||||
buf.R = R;
|
||||
buf.A = A;
|
||||
if (B)
|
||||
buf.B = *B;
|
||||
else
|
||||
buf.B = zero;
|
||||
cn_fast_hash(config::HASH_KEY_TXPROOF_V2, sizeof(config::HASH_KEY_TXPROOF_V2)-1, buf.sep);
|
||||
|
||||
if (B)
|
||||
{
|
||||
// compute X = k*B
|
||||
ge_p2 X_p2;
|
||||
ge_scalarmult(&X_p2, &k, &B_p3);
|
||||
ge_tobytes(&buf.X, &X_p2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// compute X = k*G
|
||||
ge_p3 X_p3;
|
||||
ge_scalarmult_base(&X_p3, &k);
|
||||
ge_p3_tobytes(&buf.X, &X_p3);
|
||||
}
|
||||
|
||||
// compute Y = k*A
|
||||
ge_p2 Y_p2;
|
||||
ge_scalarmult(&Y_p2, &k, &A_p3);
|
||||
ge_tobytes(&buf.Y, &Y_p2);
|
||||
|
||||
// sig.c = Hs(Msg || D || X || Y || sep || R || A || B)
|
||||
hash_to_scalar(&buf, sizeof(buf), sig.c);
|
||||
|
||||
// sig.r = k - sig.c*r
|
||||
sc_mulsub(&sig.r, &sig.c, &unwrap(r), &k);
|
||||
|
||||
memwipe(&k, sizeof(k));
|
||||
}
|
||||
|
||||
// Verify a proof: either v1 (version == 1) or v2 (version == 2)
|
||||
bool crypto_ops::check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const signature &sig, const int version) {
|
||||
// sanity check
|
||||
|
||||
@@ -131,6 +131,8 @@ namespace crypto {
|
||||
friend void generate_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, signature &);
|
||||
static void generate_tx_proof_v1(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, signature &);
|
||||
friend void generate_tx_proof_v1(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, signature &);
|
||||
static void generate_carrot_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, signature &);
|
||||
friend void generate_carrot_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, signature &);
|
||||
static bool check_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const signature &, const int);
|
||||
friend bool check_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const signature &, const int);
|
||||
static void derive_key_image_generator(const public_key &, ec_point &);
|
||||
@@ -260,6 +262,12 @@ namespace crypto {
|
||||
inline void generate_tx_proof_v1(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const secret_key &r, signature &sig) {
|
||||
crypto_ops::generate_tx_proof_v1(prefix_hash, R, A, B, D, r, sig);
|
||||
}
|
||||
/* Generation of a carrot tx proof; for carrot transactions, D is in X25519 domain (D = r*ConvertPointE(A))
|
||||
* instead of Ed25519 domain (D = r*A). This version applies ConvertPointE transformation.
|
||||
*/
|
||||
inline void generate_carrot_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const secret_key &r, signature &sig) {
|
||||
crypto_ops::generate_carrot_tx_proof(prefix_hash, R, A, B, D, r, sig);
|
||||
}
|
||||
inline bool check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const signature &sig, const int version) {
|
||||
return crypto_ops::check_tx_proof(prefix_hash, R, A, B, D, sig, version);
|
||||
}
|
||||
|
||||
@@ -202,6 +202,10 @@ namespace hw {
|
||||
const crypto::public_key &R, const crypto::public_key &A, const boost::optional<crypto::public_key> &B, const crypto::public_key &D, const crypto::secret_key &r,
|
||||
crypto::signature &sig) = 0;
|
||||
|
||||
virtual void generate_carrot_tx_proof(const crypto::hash &prefix_hash,
|
||||
const crypto::public_key &R, const crypto::public_key &A, const boost::optional<crypto::public_key> &B, const crypto::public_key &D, const crypto::secret_key &r,
|
||||
crypto::signature &sig) = 0;
|
||||
|
||||
virtual bool open_tx(crypto::secret_key &tx_key) = 0;
|
||||
|
||||
virtual void get_transaction_prefix_hash(const cryptonote::transaction_prefix& tx, crypto::hash& h) = 0;
|
||||
|
||||
@@ -282,6 +282,12 @@ namespace hw {
|
||||
crypto::generate_tx_proof(prefix_hash, R, A, B, D, r, sig);
|
||||
}
|
||||
|
||||
void device_default::generate_carrot_tx_proof(const crypto::hash &prefix_hash,
|
||||
const crypto::public_key &R, const crypto::public_key &A, const boost::optional<crypto::public_key> &B, const crypto::public_key &D, const crypto::secret_key &r,
|
||||
crypto::signature &sig) {
|
||||
crypto::generate_carrot_tx_proof(prefix_hash, R, A, B, D, r, sig);
|
||||
}
|
||||
|
||||
bool device_default::open_tx(crypto::secret_key &tx_key) {
|
||||
cryptonote::keypair txkey = cryptonote::keypair::generate(*this);
|
||||
tx_key = txkey.sec;
|
||||
|
||||
@@ -112,6 +112,10 @@ namespace hw {
|
||||
const crypto::public_key &R, const crypto::public_key &A, const boost::optional<crypto::public_key> &B, const crypto::public_key &D, const crypto::secret_key &r,
|
||||
crypto::signature &sig) override;
|
||||
|
||||
void generate_carrot_tx_proof(const crypto::hash &prefix_hash,
|
||||
const crypto::public_key &R, const crypto::public_key &A, const boost::optional<crypto::public_key> &B, const crypto::public_key &D, const crypto::secret_key &r,
|
||||
crypto::signature &sig) override;
|
||||
|
||||
bool open_tx(crypto::secret_key &tx_key) override;
|
||||
void get_transaction_prefix_hash(const cryptonote::transaction_prefix& tx, crypto::hash& h) override;
|
||||
|
||||
|
||||
@@ -1433,6 +1433,14 @@ namespace hw {
|
||||
#endif
|
||||
}
|
||||
|
||||
void device_ledger::generate_carrot_tx_proof(const crypto::hash &prefix_hash,
|
||||
const crypto::public_key &R, const crypto::public_key &A, const boost::optional<crypto::public_key> &B, const crypto::public_key &D, const crypto::secret_key &r,
|
||||
crypto::signature &sig) {
|
||||
// to-do: For now, carrot tx proofs are not supported
|
||||
AUTO_LOCK_CMD();
|
||||
crypto::generate_carrot_tx_proof(prefix_hash, R, A, B, D, r, sig);
|
||||
}
|
||||
|
||||
bool device_ledger::open_tx(crypto::secret_key &tx_key) {
|
||||
AUTO_LOCK_CMD();
|
||||
this->lock();
|
||||
|
||||
@@ -253,6 +253,10 @@ namespace hw {
|
||||
const crypto::public_key &R, const crypto::public_key &A, const boost::optional<crypto::public_key> &B, const crypto::public_key &D, const crypto::secret_key &r,
|
||||
crypto::signature &sig) override;
|
||||
|
||||
void generate_carrot_tx_proof(const crypto::hash &prefix_hash,
|
||||
const crypto::public_key &R, const crypto::public_key &A, const boost::optional<crypto::public_key> &B, const crypto::public_key &D, const crypto::secret_key &r,
|
||||
crypto::signature &sig) override;
|
||||
|
||||
bool open_tx(crypto::secret_key &tx_key) override;
|
||||
|
||||
void get_transaction_prefix_hash(const cryptonote::transaction_prefix& tx, crypto::hash& h) override;
|
||||
|
||||
+74
-104
@@ -13209,7 +13209,7 @@ std::string wallet2::get_tx_proof(const cryptonote::transaction &tx, const crypt
|
||||
hw::device &hwdev = m_account.get_device();
|
||||
rct::key aP;
|
||||
// determine if the address is found in the subaddress hash table (i.e. whether the proof is outbound or inbound)
|
||||
const bool is_out = m_subaddresses.count(address.m_spend_public_key) == 0;
|
||||
const bool is_out = m_account.get_subaddress_map_ref().count(address.m_spend_public_key) == 0;
|
||||
|
||||
const crypto::hash txid = cryptonote::get_transaction_hash(tx);
|
||||
std::string prefix_data((const char*)&txid, sizeof(crypto::hash));
|
||||
@@ -13220,19 +13220,15 @@ 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)
|
||||
|
||||
if (is_out)
|
||||
{
|
||||
std::vector<crypto::key_derivation> derivations;
|
||||
|
||||
if (is_out)
|
||||
const size_t num_sigs = 1 + additional_tx_keys.size();
|
||||
shared_secret.resize(num_sigs);
|
||||
sig.resize(num_sigs);
|
||||
|
||||
if (address.m_is_carrot)
|
||||
{
|
||||
// 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,
|
||||
@@ -13240,48 +13236,19 @@ std::string wallet2::get_tx_proof(const cryptonote::transaction &tx, const crypt
|
||||
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");
|
||||
aP = carrot::raw_byte_convert<rct::key>(s_sender_receiver_unctx);
|
||||
} else {
|
||||
hwdev.scalarmultKey(aP, rct::pk2rct(address.m_view_public_key), rct::sk2rct(tx_key));
|
||||
}
|
||||
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();
|
||||
shared_secret.resize(num_sigs);
|
||||
sig.resize(num_sigs);
|
||||
|
||||
hwdev.scalarmultKey(aP, rct::pk2rct(address.m_view_public_key), rct::sk2rct(tx_key));
|
||||
shared_secret[0] = rct::rct2pk(aP);
|
||||
crypto::public_key tx_pub_key;
|
||||
if (is_subaddress)
|
||||
if (is_subaddress && !address.m_is_carrot)
|
||||
{
|
||||
hwdev.scalarmultKey(aP, rct::pk2rct(address.m_spend_public_key), rct::sk2rct(tx_key));
|
||||
tx_pub_key = rct2pk(aP);
|
||||
hwdev.generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, address.m_spend_public_key, shared_secret[0], tx_key, sig[0]);
|
||||
}
|
||||
else if (is_subaddress && address.m_is_carrot)
|
||||
{
|
||||
hwdev.scalarmultKey(aP, rct::pk2rct(address.m_spend_public_key), rct::sk2rct(tx_key));
|
||||
tx_pub_key = rct2pk(aP);
|
||||
@@ -13290,27 +13257,42 @@ std::string wallet2::get_tx_proof(const cryptonote::transaction &tx, const crypt
|
||||
else
|
||||
{
|
||||
hwdev.secret_key_to_public_key(tx_key, tx_pub_key);
|
||||
hwdev.generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[0], tx_key, sig[0]);
|
||||
if (address.m_is_carrot) {
|
||||
hwdev.generate_carrot_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[0], tx_key, sig[0]);
|
||||
} else {
|
||||
hwdev.generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[0], tx_key, sig[0]);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < num_sigs; ++i)
|
||||
{
|
||||
hwdev.scalarmultKey(aP, rct::pk2rct(address.m_view_public_key), rct::sk2rct(additional_tx_keys[i - 1]));
|
||||
shared_secret[i] = rct::rct2pk(aP);
|
||||
if (is_subaddress)
|
||||
if (is_subaddress && !address.m_is_carrot)
|
||||
{
|
||||
hwdev.scalarmultKey(aP, rct::pk2rct(address.m_spend_public_key), rct::sk2rct(additional_tx_keys[i - 1]));
|
||||
tx_pub_key = rct2pk(aP);
|
||||
hwdev.generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, address.m_spend_public_key, shared_secret[i], additional_tx_keys[i - 1], sig[i]);
|
||||
}
|
||||
else if (is_subaddress && address.m_is_carrot)
|
||||
{
|
||||
hwdev.scalarmultKey(aP, rct::pk2rct(address.m_spend_public_key), rct::sk2rct(additional_tx_keys[i - 1]));
|
||||
tx_pub_key = rct2pk(aP);
|
||||
hwdev.generate_carrot_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, address.m_spend_public_key, shared_secret[i], additional_tx_keys[i - 1], sig[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
hwdev.secret_key_to_public_key(additional_tx_keys[i - 1], tx_pub_key);
|
||||
hwdev.generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[i], additional_tx_keys[i - 1], sig[i]);
|
||||
if (address.m_is_carrot) {
|
||||
hwdev.generate_carrot_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[i], additional_tx_keys[i - 1], sig[i]);
|
||||
} else {
|
||||
hwdev.generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[i], additional_tx_keys[i - 1], sig[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
sig_str = std::string("OutProofV2");
|
||||
}
|
||||
else
|
||||
else // is_out == false
|
||||
{
|
||||
crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx);
|
||||
THROW_WALLET_EXCEPTION_IF(tx_pub_key == null_pkey, error::wallet_internal_error, "Tx pubkey was not found");
|
||||
@@ -13320,7 +13302,7 @@ std::string wallet2::get_tx_proof(const cryptonote::transaction &tx, const crypt
|
||||
shared_secret.resize(num_sigs);
|
||||
sig.resize(num_sigs);
|
||||
|
||||
const crypto::secret_key& a = m_account.get_keys().m_view_secret_key;
|
||||
const crypto::secret_key& a = address.m_is_carrot ? m_account.get_keys().k_view_incoming : m_account.get_keys().m_view_secret_key;
|
||||
hwdev.scalarmultKey(aP, rct::pk2rct(tx_pub_key), rct::sk2rct(a));
|
||||
shared_secret[0] = rct2pk(aP);
|
||||
if (is_subaddress)
|
||||
@@ -13350,10 +13332,23 @@ std::string wallet2::get_tx_proof(const cryptonote::transaction &tx, const crypt
|
||||
|
||||
// check if this address actually received any funds
|
||||
crypto::key_derivation derivation;
|
||||
THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(shared_secret[0], rct::rct2sk(rct::I), derivation), error::wallet_internal_error, "Failed to generate key derivation");
|
||||
std::vector<crypto::key_derivation> additional_derivations(num_sigs - 1);
|
||||
for (size_t i = 1; i < num_sigs; ++i)
|
||||
THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(shared_secret[i], rct::rct2sk(rct::I), additional_derivations[i - 1]), error::wallet_internal_error, "Failed to generate key derivation");
|
||||
|
||||
if (address.m_is_carrot)
|
||||
{
|
||||
// For carrot addresses, shared_secret is already in x25519 format and can be used directly as derivation
|
||||
memcpy(&derivation, &shared_secret[0], sizeof(crypto::key_derivation));
|
||||
for (size_t i = 1; i < num_sigs; ++i)
|
||||
memcpy(&additional_derivations[i - 1], &shared_secret[i], sizeof(crypto::key_derivation));
|
||||
}
|
||||
else
|
||||
{
|
||||
// For regular addresses, generate key derivation from shared secret
|
||||
THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(shared_secret[0], rct::rct2sk(rct::I), derivation), error::wallet_internal_error, "Failed to generate key derivation");
|
||||
for (size_t i = 1; i < num_sigs; ++i)
|
||||
THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(shared_secret[i], rct::rct2sk(rct::I), additional_derivations[i - 1]), error::wallet_internal_error, "Failed to generate key derivation");
|
||||
}
|
||||
|
||||
uint64_t received;
|
||||
check_tx_key_helper(tx, derivation, additional_derivations, address, received);
|
||||
// SRCG: if this returns 0 received, but it's an AUDIT TX, then that is EXPECTED
|
||||
@@ -13424,44 +13419,6 @@ 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);
|
||||
@@ -13542,15 +13499,28 @@ bool wallet2::check_tx_proof(const cryptonote::transaction &tx, const cryptonote
|
||||
|
||||
if (std::any_of(good_signature.begin(), good_signature.end(), [](int i) { return i > 0; }))
|
||||
{
|
||||
// obtain key derivation by multiplying scalar 1 to the shared secret
|
||||
// obtain key derivation by multiplying scalar 1 to the shared secret (or use directly for carrot)
|
||||
crypto::key_derivation derivation;
|
||||
if (good_signature[0])
|
||||
THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(shared_secret[0], rct::rct2sk(rct::I), derivation), error::wallet_internal_error, "Failed to generate key derivation");
|
||||
|
||||
std::vector<crypto::key_derivation> additional_derivations(num_sigs - 1);
|
||||
for (size_t i = 1; i < num_sigs; ++i)
|
||||
if (good_signature[i])
|
||||
THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(shared_secret[i], rct::rct2sk(rct::I), additional_derivations[i - 1]), error::wallet_internal_error, "Failed to generate key derivation");
|
||||
|
||||
if (address.m_is_carrot)
|
||||
{
|
||||
// For carrot addresses, shared_secret is already in x25519 format and can be used directly as derivation
|
||||
if (good_signature[0])
|
||||
memcpy(&derivation, &shared_secret[0], sizeof(crypto::key_derivation));
|
||||
for (size_t i = 1; i < num_sigs; ++i)
|
||||
if (good_signature[i])
|
||||
memcpy(&additional_derivations[i - 1], &shared_secret[i], sizeof(crypto::key_derivation));
|
||||
}
|
||||
else
|
||||
{
|
||||
// For regular addresses, generate key derivation from shared secret
|
||||
if (good_signature[0])
|
||||
THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(shared_secret[0], rct::rct2sk(rct::I), derivation), error::wallet_internal_error, "Failed to generate key derivation");
|
||||
for (size_t i = 1; i < num_sigs; ++i)
|
||||
if (good_signature[i])
|
||||
THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(shared_secret[i], rct::rct2sk(rct::I), additional_derivations[i - 1]), error::wallet_internal_error, "Failed to generate key derivation");
|
||||
}
|
||||
|
||||
check_tx_key_helper(tx, derivation, additional_derivations, address, received);
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user