mirror of
https://github.com/monero-project/monero.git
synced 2025-01-28 18:56:31 +02:00
309 lines
11 KiB
C
309 lines
11 KiB
C
|
// Copyright (c) 2024, The Monero Project
|
||
|
//
|
||
|
// All rights reserved.
|
||
|
//
|
||
|
// Redistribution and use in source and binary forms, with or without modification, are
|
||
|
// permitted provided that the following conditions are met:
|
||
|
//
|
||
|
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||
|
// conditions and the following disclaimer.
|
||
|
//
|
||
|
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||
|
// of conditions and the following disclaimer in the documentation and/or other
|
||
|
// materials provided with the distribution.
|
||
|
//
|
||
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||
|
// used to endorse or promote products derived from this software without specific
|
||
|
// prior written permission.
|
||
|
//
|
||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||
|
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||
|
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||
|
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||
|
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include "carrot_core/carrot_enote_scan.h"
|
||
|
#include "carrot_core/device_ram_borrowed.h"
|
||
|
#include "carrot_core/enote_utils.h"
|
||
|
#include "carrot_core/payment_proposal.h"
|
||
|
#include "crypto/crypto.h"
|
||
|
#include "crypto/x25519.h"
|
||
|
#include "device/device.hpp"
|
||
|
#include "performance_tests.h"
|
||
|
#include "ringct/rctOps.h"
|
||
|
#include "ringct/rctTypes.h"
|
||
|
|
||
|
//---------------------------------------------------------------------------------------------------------------------
|
||
|
//---------------------------------------------------------------------------------------------------------------------
|
||
|
//---------------------------------------------------------------------------------------------------------------------
|
||
|
|
||
|
struct ParamsShuttleViewScan final : public ParamsShuttle
|
||
|
{
|
||
|
bool test_view_tag_check{false};
|
||
|
};
|
||
|
|
||
|
/// cryptonote view key scanning (with optional view tag check)
|
||
|
/// test:
|
||
|
/// - sender-receiver secret: kv*R_t
|
||
|
/// - view tag: H1(kv*R_t)
|
||
|
/// - (optional): return here to mimick a view tag check failure
|
||
|
/// - Ks_nom = Ko - H(kv*R_t)*G
|
||
|
/// - Ks ?= Ks_nom
|
||
|
class test_view_scan_cn
|
||
|
{
|
||
|
public:
|
||
|
static const size_t loop_count = 1000;
|
||
|
|
||
|
bool init(const ParamsShuttleViewScan ¶ms)
|
||
|
{
|
||
|
m_test_view_tag_check = params.test_view_tag_check;
|
||
|
|
||
|
// kv, Ks = ks*G, R_t = r_t*G
|
||
|
m_view_secret_key = rct::rct2sk(rct::skGen());
|
||
|
m_spendkey = rct::rct2pk(rct::pkGen());
|
||
|
m_tx_pub_key = rct::rct2pk(rct::pkGen());
|
||
|
|
||
|
// kv*R_t (i.e. r_t*Kv)
|
||
|
crypto::key_derivation derivation;
|
||
|
crypto::generate_key_derivation(m_tx_pub_key, m_view_secret_key, derivation);
|
||
|
|
||
|
// Ko = H(kv*R_t, t)*G + Ks
|
||
|
crypto::derive_public_key(derivation, 0, m_spendkey, m_onetime_address);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool test()
|
||
|
{
|
||
|
// kv*R_t
|
||
|
crypto::key_derivation derivation;
|
||
|
crypto::generate_key_derivation(m_tx_pub_key, m_view_secret_key, derivation);
|
||
|
|
||
|
// view tag: H1(kv*R_t, t)
|
||
|
crypto::view_tag mock_view_tag;
|
||
|
crypto::derive_view_tag(derivation, 0, mock_view_tag);
|
||
|
|
||
|
// check: early return after computing a view tag (e.g. if nominal view tag doesn't match enote view tag)
|
||
|
if (m_test_view_tag_check)
|
||
|
return true;
|
||
|
|
||
|
// Ks_nom = Ko - H(kv*R_t, t)*G
|
||
|
crypto::public_key nominal_spendkey;
|
||
|
crypto::derive_subaddress_public_key(m_onetime_address, derivation, 0, nominal_spendkey);
|
||
|
|
||
|
// Ks_nom ?= Ks
|
||
|
return nominal_spendkey == m_spendkey;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
/// kv
|
||
|
crypto::secret_key m_view_secret_key;
|
||
|
/// Ks = ks*G
|
||
|
crypto::public_key m_spendkey;
|
||
|
|
||
|
/// R_t = r_t*G
|
||
|
crypto::public_key m_tx_pub_key;
|
||
|
/// Ko = H(kv*R_t, t)*G + Ks
|
||
|
crypto::public_key m_onetime_address;
|
||
|
|
||
|
bool m_test_view_tag_check;
|
||
|
};
|
||
|
|
||
|
//---------------------------------------------------------------------------------------------------------------------
|
||
|
//---------------------------------------------------------------------------------------------------------------------
|
||
|
//---------------------------------------------------------------------------------------------------------------------
|
||
|
|
||
|
////
|
||
|
// cryptonote view key scanning using optimized crypto library (with optional view tag check)
|
||
|
// note: this relies on 'default hwdev' to auto-find the current machine's best available crypto implementation
|
||
|
///
|
||
|
class test_view_scan_cn_optimized
|
||
|
{
|
||
|
public:
|
||
|
static const size_t loop_count = 1000;
|
||
|
|
||
|
bool init(const ParamsShuttleViewScan ¶ms)
|
||
|
{
|
||
|
m_test_view_tag_check = params.test_view_tag_check;
|
||
|
|
||
|
// kv, Ks = ks*G, R_t = r_t*G
|
||
|
m_view_secret_key = rct::rct2sk(rct::skGen());
|
||
|
m_spendkey = rct::rct2pk(rct::pkGen());
|
||
|
m_tx_pub_key = rct::rct2pk(rct::pkGen());
|
||
|
|
||
|
// kv*R_t (i.e. r_t*Kv)
|
||
|
crypto::key_derivation derivation;
|
||
|
m_hwdev.generate_key_derivation(m_tx_pub_key, m_view_secret_key, derivation);
|
||
|
|
||
|
// Ko = H(kv*R_t, t)*G + Ks
|
||
|
m_hwdev.derive_public_key(derivation, 0, m_spendkey, m_onetime_address);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool test()
|
||
|
{
|
||
|
// kv*R_t
|
||
|
crypto::key_derivation derivation;
|
||
|
m_hwdev.generate_key_derivation(m_tx_pub_key, m_view_secret_key, derivation);
|
||
|
|
||
|
// view tag: H1(kv*R_t, t)
|
||
|
crypto::view_tag mock_view_tag;
|
||
|
m_hwdev.derive_view_tag(derivation, 0, mock_view_tag);
|
||
|
|
||
|
// check: early return after computing a view tag (e.g. if nominal view tag doesn't match enote view tag)
|
||
|
if (m_test_view_tag_check)
|
||
|
return true;
|
||
|
|
||
|
// Ks_nom = Ko - H(kv*R_t, t)*G
|
||
|
crypto::public_key nominal_spendkey;
|
||
|
m_hwdev.derive_subaddress_public_key(m_onetime_address, derivation, 0, nominal_spendkey);
|
||
|
|
||
|
// Ks_nom ?= Ks
|
||
|
return nominal_spendkey == m_spendkey;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
hw::device &m_hwdev{hw::get_device("default")};
|
||
|
|
||
|
/// kv
|
||
|
crypto::secret_key m_view_secret_key;
|
||
|
/// Ks = ks*G
|
||
|
crypto::public_key m_spendkey;
|
||
|
|
||
|
/// R_t = r_t*G
|
||
|
crypto::public_key m_tx_pub_key;
|
||
|
/// Ko = H(kv*R_t, t)*G + Ks
|
||
|
crypto::public_key m_onetime_address;
|
||
|
|
||
|
bool m_test_view_tag_check;
|
||
|
};
|
||
|
|
||
|
//---------------------------------------------------------------------------------------------------------------------
|
||
|
//---------------------------------------------------------------------------------------------------------------------
|
||
|
//---------------------------------------------------------------------------------------------------------------------
|
||
|
|
||
|
/// carrot view key scanning
|
||
|
class test_view_scan_carrot
|
||
|
{
|
||
|
public:
|
||
|
static const size_t loop_count = 1000;
|
||
|
|
||
|
test_view_scan_carrot(): m_k_view_dev(m_k_view_incoming) {}
|
||
|
|
||
|
bool init(const ParamsShuttleViewScan ¶ms)
|
||
|
{
|
||
|
m_test_view_tag_check = params.test_view_tag_check;
|
||
|
|
||
|
m_k_view_incoming = rct::rct2sk(rct::skGen());
|
||
|
|
||
|
m_account_spend_pubkey = rct::rct2pk(rct::pkGen());
|
||
|
const crypto::public_key account_view_pubkey = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(m_account_spend_pubkey), rct::sk2rct(m_k_view_incoming)));
|
||
|
|
||
|
carrot::CarrotDestinationV1 subaddress;
|
||
|
carrot::make_carrot_subaddress_v1(m_account_spend_pubkey, account_view_pubkey, {}, 88, 88, subaddress);
|
||
|
|
||
|
const carrot::CarrotPaymentProposalV1 payment_proposal{
|
||
|
.destination = subaddress,
|
||
|
.amount = crypto::rand<rct::xmr_amount>(),
|
||
|
.randomness = carrot::gen_janus_anchor()
|
||
|
};
|
||
|
|
||
|
carrot::RCTOutputEnoteProposal output_proposal;
|
||
|
carrot::get_output_proposal_normal_v1(payment_proposal,
|
||
|
{},
|
||
|
output_proposal,
|
||
|
m_encrypted_payment_id);
|
||
|
m_enote = output_proposal.enote;
|
||
|
|
||
|
crypto::x25519_pubkey s_sender_receiver_unctx;
|
||
|
carrot::make_carrot_uncontextualized_shared_key_receiver(m_k_view_incoming,
|
||
|
m_enote.enote_ephemeral_pubkey,
|
||
|
s_sender_receiver_unctx);
|
||
|
|
||
|
crypto::secret_key _1, _2, _3;
|
||
|
crypto::public_key recovered_address_spend_pubkey;
|
||
|
rct::xmr_amount recovered_amount;
|
||
|
carrot::payment_id_t recovered_payment_id;
|
||
|
carrot::CarrotEnoteType recovered_enote_type;
|
||
|
if (!carrot::try_scan_carrot_enote_external(m_enote,
|
||
|
m_encrypted_payment_id,
|
||
|
s_sender_receiver_unctx,
|
||
|
m_k_view_dev,
|
||
|
m_account_spend_pubkey,
|
||
|
_1,
|
||
|
_2,
|
||
|
recovered_address_spend_pubkey,
|
||
|
recovered_amount,
|
||
|
_3,
|
||
|
recovered_payment_id,
|
||
|
recovered_enote_type))
|
||
|
return false;
|
||
|
|
||
|
if (recovered_address_spend_pubkey != subaddress.address_spend_pubkey)
|
||
|
return false;
|
||
|
|
||
|
if (recovered_amount != payment_proposal.amount)
|
||
|
return false;
|
||
|
|
||
|
if (recovered_payment_id != carrot::null_payment_id)
|
||
|
return false;
|
||
|
|
||
|
if (recovered_enote_type != carrot::CarrotEnoteType::PAYMENT)
|
||
|
return false;
|
||
|
|
||
|
if (m_test_view_tag_check)
|
||
|
m_enote.view_tag.bytes[0] ^= 1;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool test()
|
||
|
{
|
||
|
crypto::x25519_pubkey s_sender_receiver_unctx;
|
||
|
carrot::make_carrot_uncontextualized_shared_key_receiver(m_k_view_incoming,
|
||
|
m_enote.enote_ephemeral_pubkey,
|
||
|
s_sender_receiver_unctx);
|
||
|
|
||
|
crypto::secret_key _1, _2, _3;
|
||
|
crypto::public_key recovered_address_spend_pubkey;
|
||
|
rct::xmr_amount recovered_amount;
|
||
|
carrot::payment_id_t recovered_payment_id;
|
||
|
carrot::CarrotEnoteType recovered_enote_type;
|
||
|
const bool scan_success = carrot::try_scan_carrot_enote_external(m_enote,
|
||
|
m_encrypted_payment_id,
|
||
|
s_sender_receiver_unctx,
|
||
|
m_k_view_dev,
|
||
|
m_account_spend_pubkey,
|
||
|
_1,
|
||
|
_2,
|
||
|
recovered_address_spend_pubkey,
|
||
|
recovered_amount,
|
||
|
_3,
|
||
|
recovered_payment_id,
|
||
|
recovered_enote_type);
|
||
|
|
||
|
return scan_success ^ m_test_view_tag_check;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
crypto::public_key m_account_spend_pubkey;
|
||
|
crypto::secret_key m_k_view_incoming;
|
||
|
carrot::view_incoming_key_ram_borrowed_device m_k_view_dev;
|
||
|
|
||
|
carrot::CarrotEnoteV1 m_enote;
|
||
|
carrot::encrypted_payment_id_t m_encrypted_payment_id;
|
||
|
|
||
|
bool m_test_view_tag_check;
|
||
|
};
|
||
|
|
||
|
//---------------------------------------------------------------------------------------------------------------------
|
||
|
//---------------------------------------------------------------------------------------------------------------------
|
||
|
//---------------------------------------------------------------------------------------------------------------------
|