From f9be7571c25f8ade777a4fa00da944b517556dea Mon Sep 17 00:00:00 2001 From: jeffro256 Date: Tue, 26 Nov 2024 15:57:04 -0600 Subject: [PATCH] scan using a device interface --- src/carrot_core/CMakeLists.txt | 1 + src/carrot_core/account_secrets.cpp | 2 +- src/carrot_core/account_secrets.h | 2 +- src/carrot_core/address_utils.cpp | 2 +- src/carrot_core/address_utils.h | 2 +- src/carrot_core/carrot_enote_scan.cpp | 121 +++++++++++++++++++----- src/carrot_core/carrot_enote_scan.h | 16 +++- src/carrot_core/core_types.cpp | 2 +- src/carrot_core/core_types.h | 2 +- src/carrot_core/destination.h | 2 +- src/carrot_core/device.h | 10 +- src/carrot_core/device_ram_borrowed.cpp | 90 ++++++++++++++++++ src/carrot_core/device_ram_borrowed.h | 86 +++++++++++++++++ src/carrot_core/enote_utils.cpp | 102 +------------------- src/carrot_core/enote_utils.h | 62 +----------- src/carrot_core/hash_functions.cpp | 2 +- src/carrot_core/hash_functions.h | 2 +- src/carrot_core/payment_proposal.cpp | 2 +- src/carrot_core/payment_proposal.h | 2 +- src/carrot_core/transcript_fixed.h | 2 +- tests/unit_tests/carrot_core.cpp | 23 +++-- 21 files changed, 325 insertions(+), 210 deletions(-) create mode 100644 src/carrot_core/device_ram_borrowed.cpp create mode 100644 src/carrot_core/device_ram_borrowed.h diff --git a/src/carrot_core/CMakeLists.txt b/src/carrot_core/CMakeLists.txt index c71de2a68..e81cf1a46 100644 --- a/src/carrot_core/CMakeLists.txt +++ b/src/carrot_core/CMakeLists.txt @@ -32,6 +32,7 @@ set(carrot_core_sources carrot_enote_scan.cpp core_types.cpp destination.cpp + device_ram_borrowed.cpp enote_utils.cpp hash_functions.cpp payment_proposal.cpp) diff --git a/src/carrot_core/account_secrets.cpp b/src/carrot_core/account_secrets.cpp index f393821f6..2f8b16d56 100644 --- a/src/carrot_core/account_secrets.cpp +++ b/src/carrot_core/account_secrets.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2022, The Monero Project +// Copyright (c) 2024, The Monero Project // // All rights reserved. // diff --git a/src/carrot_core/account_secrets.h b/src/carrot_core/account_secrets.h index 460f8beeb..4fef1c55c 100644 --- a/src/carrot_core/account_secrets.h +++ b/src/carrot_core/account_secrets.h @@ -1,4 +1,4 @@ -// Copyright (c) 2022, The Monero Project +// Copyright (c) 2024, The Monero Project // // All rights reserved. // diff --git a/src/carrot_core/address_utils.cpp b/src/carrot_core/address_utils.cpp index 09a2bfe81..bfa429f31 100644 --- a/src/carrot_core/address_utils.cpp +++ b/src/carrot_core/address_utils.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2022, The Monero Project +// Copyright (c) 2024, The Monero Project // // All rights reserved. // diff --git a/src/carrot_core/address_utils.h b/src/carrot_core/address_utils.h index 4f66725bf..6dbf8928f 100644 --- a/src/carrot_core/address_utils.h +++ b/src/carrot_core/address_utils.h @@ -1,4 +1,4 @@ -// Copyright (c) 2022, The Monero Project +// Copyright (c) 2024, The Monero Project // // All rights reserved. // diff --git a/src/carrot_core/carrot_enote_scan.cpp b/src/carrot_core/carrot_enote_scan.cpp index 09f6c5d2b..478a71fea 100644 --- a/src/carrot_core/carrot_enote_scan.cpp +++ b/src/carrot_core/carrot_enote_scan.cpp @@ -32,6 +32,7 @@ #include "carrot_enote_scan.h" //local headers +#include "crypto/generators.h" #include "enote_utils.h" #include "ringct/rctOps.h" @@ -44,10 +45,9 @@ namespace carrot { //------------------------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------------------------- -static bool try_scan_carrot_non_coinbase_no_janus(const CarrotEnoteV1 &enote, +static bool try_scan_carrot_non_coinbase_core(const CarrotEnoteV1 &enote, const std::optional encrypted_payment_id, - const input_context_t &input_context, - const unsigned char s_sender_receiver_unctx[32], + const crypto::hash &s_sender_receiver, crypto::secret_key &sender_extension_g_out, crypto::secret_key &sender_extension_t_out, crypto::public_key &address_spend_pubkey_out, @@ -57,17 +57,6 @@ static bool try_scan_carrot_non_coinbase_no_janus(const CarrotEnoteV1 &enote, CarrotEnoteType &enote_type_out, janus_anchor_t &nominal_janus_anchor_out) { - // if vt' != vt, then FAIL - if (!test_carrot_view_tag(s_sender_receiver_unctx, input_context, enote.onetime_address, enote.view_tag)) - return false; - - // s^ctx_sr = H_32(s_sr, D_e, input_context) - crypto::hash s_sender_receiver; - make_carrot_sender_receiver_secret(s_sender_receiver_unctx, - enote.enote_ephemeral_pubkey, - input_context, - s_sender_receiver); - // if cannot recompute C_a, then FAIL if (!try_get_carrot_amount(s_sender_receiver, enote.amount_enc, @@ -109,9 +98,68 @@ static bool try_scan_carrot_non_coinbase_no_janus(const CarrotEnoteV1 &enote, } //------------------------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------------------------- +bool verify_carrot_janus_protection(const input_context_t &input_context, + const crypto::public_key &onetime_address, + const view_incoming_key_device &k_view_dev, + const crypto::public_key &account_spend_pubkey, + const crypto::public_key &nominal_address_spend_pubkey, + const crypto::x25519_pubkey &enote_ephemeral_pubkey, + const janus_anchor_t &nominal_anchor, + payment_id_t &nominal_payment_id_inout) +{ + const bool is_subaddress = nominal_address_spend_pubkey != account_spend_pubkey; + + // make K^j_v' + crypto::public_key nominal_address_view_pubkey; + if (is_subaddress) + { + // K^j_v' = k_v K^j_s' + if (!k_view_dev.view_key_scalar_mult_ed25519(nominal_address_spend_pubkey, nominal_address_view_pubkey)) + return false; + } + else // cryptonote address + { + // K^j_v' = k_v G + if (!k_view_dev.view_key_scalar_mult_ed25519(crypto::get_G(), nominal_address_view_pubkey)) + return false; + } + + // if can recompute D_e with pid', then PASS + if (verify_carrot_external_janus_protection(nominal_anchor, + input_context, + nominal_address_spend_pubkey, + nominal_address_view_pubkey, + is_subaddress, + nominal_payment_id_inout, + enote_ephemeral_pubkey)) + return true; + + // if can recompute D_e with null pid, then PASS + nominal_payment_id_inout = null_payment_id; + if (verify_carrot_external_janus_protection(nominal_anchor, + input_context, + nominal_address_spend_pubkey, + nominal_address_view_pubkey, + is_subaddress, + null_payment_id, + enote_ephemeral_pubkey)) + return true; + + // anchor_sp = H_16(D_e, input_context, Ko, k_v, K_s) + janus_anchor_t expected_special_anchor; + k_view_dev.make_janus_anchor_special(enote_ephemeral_pubkey, + input_context, + onetime_address, + account_spend_pubkey, + expected_special_anchor); + + // attempt special janus check: anchor_sp ?= anchor' + return expected_special_anchor == nominal_anchor; +} +//------------------------------------------------------------------------------------------------------------------- bool try_scan_carrot_coinbase_enote(const CarrotCoinbaseEnoteV1 &enote, const crypto::x25519_pubkey &s_sender_receiver_unctx, - const crypto::secret_key &k_view, + const view_incoming_key_device &k_view_dev, const crypto::public_key &account_spend_pubkey, crypto::secret_key &sender_extension_g_out, crypto::secret_key &sender_extension_t_out, @@ -166,7 +214,7 @@ bool try_scan_carrot_coinbase_enote(const CarrotCoinbaseEnoteV1 &enote, payment_id_t dummy_payment_id = null_payment_id; if (!verify_carrot_janus_protection(input_context, enote.onetime_address, - k_view, + k_view_dev, account_spend_pubkey, address_spend_pubkey_out, enote.enote_ephemeral_pubkey, @@ -180,7 +228,7 @@ bool try_scan_carrot_coinbase_enote(const CarrotCoinbaseEnoteV1 &enote, bool try_scan_carrot_enote_external(const CarrotEnoteV1 &enote, const std::optional encrypted_payment_id, const crypto::x25519_pubkey &s_sender_receiver_unctx, - const crypto::secret_key &k_view, + const view_incoming_key_device &k_view_dev, const crypto::public_key &account_spend_pubkey, crypto::secret_key &sender_extension_g_out, crypto::secret_key &sender_extension_t_out, @@ -194,12 +242,22 @@ bool try_scan_carrot_enote_external(const CarrotEnoteV1 &enote, input_context_t input_context; make_carrot_input_context(enote.tx_first_key_image, input_context); + // test view tag + if (!test_carrot_view_tag(s_sender_receiver_unctx.data, input_context, enote.onetime_address, enote.view_tag)) + return false; + + // s^ctx_sr = H_32(s_sr, D_e, input_context) + crypto::hash s_sender_receiver; + make_carrot_sender_receiver_secret(s_sender_receiver_unctx.data, + enote.enote_ephemeral_pubkey, + input_context, + s_sender_receiver); + // do core scanning janus_anchor_t nominal_anchor; - if (!try_scan_carrot_non_coinbase_no_janus(enote, + if (!try_scan_carrot_non_coinbase_core(enote, encrypted_payment_id, - input_context, - s_sender_receiver_unctx.data, + s_sender_receiver, sender_extension_g_out, sender_extension_t_out, address_spend_pubkey_out, @@ -213,7 +271,7 @@ bool try_scan_carrot_enote_external(const CarrotEnoteV1 &enote, // verify Janus attack protection if (!verify_carrot_janus_protection(input_context, enote.onetime_address, - k_view, + k_view_dev, account_spend_pubkey, address_spend_pubkey_out, enote.enote_ephemeral_pubkey, @@ -225,7 +283,7 @@ bool try_scan_carrot_enote_external(const CarrotEnoteV1 &enote, } //------------------------------------------------------------------------------------------------------------------- bool try_scan_carrot_enote_internal(const CarrotEnoteV1 &enote, - const crypto::secret_key &s_view_balance, + const view_balance_secret_device &s_view_balance_dev, crypto::secret_key &sender_extension_g_out, crypto::secret_key &sender_extension_t_out, crypto::public_key &address_spend_pubkey_out, @@ -237,13 +295,26 @@ bool try_scan_carrot_enote_internal(const CarrotEnoteV1 &enote, input_context_t input_context; make_carrot_input_context(enote.tx_first_key_image, input_context); + // vt = H_3(s_sr || input_context || Ko) + view_tag_t nominal_view_tag; + s_view_balance_dev.make_internal_view_tag(input_context, enote.onetime_address, nominal_view_tag); + + // test view tag + if (nominal_view_tag != enote.view_tag) + return false; + + // s^ctx_sr = H_32(s_vb, D_e, input_context) + crypto::hash s_sender_receiver; + s_view_balance_dev.make_internal_sender_receiver_secret(enote.enote_ephemeral_pubkey, + input_context, + s_sender_receiver); + // do core scanning janus_anchor_t nominal_anchor; payment_id_t dummy_payment_id; - if (!try_scan_carrot_non_coinbase_no_janus(enote, + if (!try_scan_carrot_non_coinbase_core(enote, std::nullopt, - input_context, - to_bytes(s_view_balance), + s_sender_receiver, sender_extension_g_out, sender_extension_t_out, address_spend_pubkey_out, diff --git a/src/carrot_core/carrot_enote_scan.h b/src/carrot_core/carrot_enote_scan.h index 01ae7947c..3d1e29fe7 100644 --- a/src/carrot_core/carrot_enote_scan.h +++ b/src/carrot_core/carrot_enote_scan.h @@ -32,6 +32,7 @@ //local headers #include "carrot_enote_types.h" +#include "device.h" //third party headers @@ -43,9 +44,18 @@ namespace carrot { +bool verify_carrot_janus_protection(const input_context_t &input_context, + const crypto::public_key &onetime_address, + const view_incoming_key_device &k_view_dev, + const crypto::public_key &account_spend_pubkey, + const crypto::public_key &nominal_address_spend_pubkey, + const crypto::x25519_pubkey &enote_ephemeral_pubkey, + const janus_anchor_t &nominal_anchor, + payment_id_t &nominal_payment_id_inout); + bool try_scan_carrot_coinbase_enote(const CarrotCoinbaseEnoteV1 &enote, const crypto::x25519_pubkey &s_sender_receiver_unctx, - const crypto::secret_key &k_view, + const view_incoming_key_device &k_view_dev, const crypto::public_key &account_spend_pubkey, crypto::secret_key &sender_extension_g_out, crypto::secret_key &sender_extension_t_out, @@ -54,7 +64,7 @@ bool try_scan_carrot_coinbase_enote(const CarrotCoinbaseEnoteV1 &enote, bool try_scan_carrot_enote_external(const CarrotEnoteV1 &enote, const std::optional encrypted_payment_id, const crypto::x25519_pubkey &s_sender_receiver_unctx, - const crypto::secret_key &k_view, + const view_incoming_key_device &k_view_dev, const crypto::public_key &account_spend_pubkey, crypto::secret_key &sender_extension_g_out, crypto::secret_key &sender_extension_t_out, @@ -65,7 +75,7 @@ bool try_scan_carrot_enote_external(const CarrotEnoteV1 &enote, CarrotEnoteType &enote_type_out); bool try_scan_carrot_enote_internal(const CarrotEnoteV1 &enote, - const crypto::secret_key &s_view_balance, + const view_balance_secret_device &s_view_balance_dev, crypto::secret_key &sender_extension_g_out, crypto::secret_key &sender_extension_t_out, crypto::public_key &address_spend_pubkey_out, diff --git a/src/carrot_core/core_types.cpp b/src/carrot_core/core_types.cpp index 2d91a1ba7..2145f4dc8 100644 --- a/src/carrot_core/core_types.cpp +++ b/src/carrot_core/core_types.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2022, The Monero Project +// Copyright (c) 2024, The Monero Project // // All rights reserved. // diff --git a/src/carrot_core/core_types.h b/src/carrot_core/core_types.h index d461f4168..8dc8a0e67 100644 --- a/src/carrot_core/core_types.h +++ b/src/carrot_core/core_types.h @@ -1,4 +1,4 @@ -// Copyright (c) 2022, The Monero Project +// Copyright (c) 2024, The Monero Project // // All rights reserved. // diff --git a/src/carrot_core/destination.h b/src/carrot_core/destination.h index 53f5cda0e..98a5ea407 100644 --- a/src/carrot_core/destination.h +++ b/src/carrot_core/destination.h @@ -1,4 +1,4 @@ -// Copyright (c) 2022, The Monero Project +// Copyright (c) 2024, The Monero Project // // All rights reserved. // diff --git a/src/carrot_core/device.h b/src/carrot_core/device.h index 09eec74fe..c305128f7 100644 --- a/src/carrot_core/device.h +++ b/src/carrot_core/device.h @@ -1,4 +1,4 @@ -// Copyright (c) 2022, The Monero Project +// Copyright (c) 2024, The Monero Project // // All rights reserved. // @@ -90,7 +90,7 @@ struct device_error: public std::runtime_error char buf[384]; snprintf(buf, sizeof(buf), "%s %s device error (%d), at %s(): %s", - code, dev_make, dev_model, func_called, msg); + dev_make.c_str(), dev_model.c_str(), code, func_called.c_str(), msg.c_str()); return {buf}; } @@ -119,7 +119,7 @@ struct view_incoming_key_device * return: true on success, false on failure (e.g. unable to decompress point) */ virtual bool view_key_8_scalar_mult_x25519(const crypto::x25519_pubkey &D, - crypto::public_key &kv8D) const = 0; + crypto::x25519_pubkey &kv8D) const = 0; /** * brief: make_janus_anchor_special - make a janus anchor for "special" enotes @@ -133,6 +133,8 @@ struct view_incoming_key_device const crypto::public_key &onetime_address, const crypto::public_key &account_spend_pubkey, janus_anchor_t &anchor_special_out) const = 0; + + virtual ~view_incoming_key_device() = default; }; struct view_balance_secret_device @@ -156,6 +158,8 @@ struct view_balance_secret_device virtual void make_internal_sender_receiver_secret(const crypto::x25519_pubkey &enote_ephemeral_pubkey, const input_context_t &input_context, crypto::hash &s_sender_receiver_out) const = 0; + + virtual ~view_balance_secret_device() = default; }; } //namespace carrot diff --git a/src/carrot_core/device_ram_borrowed.cpp b/src/carrot_core/device_ram_borrowed.cpp new file mode 100644 index 000000000..269acd08d --- /dev/null +++ b/src/carrot_core/device_ram_borrowed.cpp @@ -0,0 +1,90 @@ +// 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. + +//pair header +#include "device_ram_borrowed.h" + +//local headers +#include "enote_utils.h" +#include "ringct/rctOps.h" + +//third party headers + +//standard headers + + +namespace carrot +{ +//------------------------------------------------------------------------------------------------------------------- +bool view_incoming_key_ram_borrowed_device::view_key_scalar_mult_ed25519(const crypto::public_key &P, + crypto::public_key &kvP) const +{ + kvP = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(P), rct::sk2rct(m_k_view_incoming))); + return true; +} +//------------------------------------------------------------------------------------------------------------------- +bool view_incoming_key_ram_borrowed_device::view_key_8_scalar_mult_x25519(const crypto::x25519_pubkey &D, + crypto::x25519_pubkey &kv8D) const +{ + return make_carrot_uncontextualized_shared_key_receiver(m_k_view_incoming, D, kv8D); +} +//------------------------------------------------------------------------------------------------------------------- +void view_incoming_key_ram_borrowed_device::make_janus_anchor_special( + const crypto::x25519_pubkey &enote_ephemeral_pubkey, + const input_context_t &input_context, + const crypto::public_key &onetime_address, + const crypto::public_key &account_spend_pubkey, + janus_anchor_t &anchor_special_out) const +{ + return make_carrot_janus_anchor_special(enote_ephemeral_pubkey, + input_context, + onetime_address, + m_k_view_incoming, + account_spend_pubkey, + anchor_special_out); +} +//------------------------------------------------------------------------------------------------------------------- +void view_balance_secret_ram_borrowed_device::make_internal_view_tag(const input_context_t &input_context, + const crypto::public_key &onetime_address, + view_tag_t &view_tag_out) const +{ + make_carrot_view_tag(to_bytes(m_s_view_balance), input_context, onetime_address, view_tag_out); +} +//------------------------------------------------------------------------------------------------------------------- +void view_balance_secret_ram_borrowed_device::make_internal_sender_receiver_secret( + const crypto::x25519_pubkey &enote_ephemeral_pubkey, + const input_context_t &input_context, + crypto::hash &s_sender_receiver_out) const +{ + make_carrot_sender_receiver_secret(to_bytes(m_s_view_balance), + enote_ephemeral_pubkey, + input_context, + s_sender_receiver_out); +} +//------------------------------------------------------------------------------------------------------------------- +} //namespace carrot diff --git a/src/carrot_core/device_ram_borrowed.h b/src/carrot_core/device_ram_borrowed.h new file mode 100644 index 000000000..c0a51755e --- /dev/null +++ b/src/carrot_core/device_ram_borrowed.h @@ -0,0 +1,86 @@ +// 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. + +//! @file Carrot device implementations for in-memory keys & secrets + +#pragma once + +//local headers +#include "device.h" + +//third party headers + +//standard headers + +//forward declarations + + +namespace carrot +{ + +class view_incoming_key_ram_borrowed_device: public view_incoming_key_device +{ +public: + view_incoming_key_ram_borrowed_device(const crypto::secret_key &k_view_incoming): + m_k_view_incoming(k_view_incoming) {} + + bool view_key_scalar_mult_ed25519(const crypto::public_key &P, + crypto::public_key &kvP) const override; + + bool view_key_8_scalar_mult_x25519(const crypto::x25519_pubkey &D, + crypto::x25519_pubkey &kv8D) const override; + + void make_janus_anchor_special(const crypto::x25519_pubkey &enote_ephemeral_pubkey, + const input_context_t &input_context, + const crypto::public_key &onetime_address, + const crypto::public_key &account_spend_pubkey, + janus_anchor_t &anchor_special_out) const override; + +private: + const crypto::secret_key &m_k_view_incoming; +}; + +class view_balance_secret_ram_borrowed_device: public view_balance_secret_device +{ +public: + view_balance_secret_ram_borrowed_device(const crypto::secret_key &s_view_balance): + m_s_view_balance(s_view_balance) {} + + void make_internal_view_tag(const input_context_t &input_context, + const crypto::public_key &onetime_address, + view_tag_t &view_tag_out) const override; + + void make_internal_sender_receiver_secret(const crypto::x25519_pubkey &enote_ephemeral_pubkey, + const input_context_t &input_context, + crypto::hash &s_sender_receiver_out) const override; + +private: + const crypto::secret_key &m_s_view_balance; +}; + +} //namespace carrot diff --git a/src/carrot_core/enote_utils.cpp b/src/carrot_core/enote_utils.cpp index 9d846592b..72f24cff5 100644 --- a/src/carrot_core/enote_utils.cpp +++ b/src/carrot_core/enote_utils.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2022, The Monero Project +// Copyright (c) 2024, The Monero Project // // All rights reserved. // @@ -449,7 +449,7 @@ bool try_get_carrot_amount(const crypto::hash &s_sender_receiver, return false; } //------------------------------------------------------------------------------------------------------------------- -bool verify_external_carrot_janus_protection(const janus_anchor_t &nominal_anchor, +bool verify_carrot_external_janus_protection(const janus_anchor_t &nominal_anchor, const input_context_t &input_context, const crypto::public_key &nominal_address_spend_pubkey, const crypto::public_key &nominal_address_view_pubkey, @@ -480,102 +480,4 @@ bool verify_external_carrot_janus_protection(const janus_anchor_t &nominal_ancho return nominal_enote_ephemeral_pubkey == enote_ephemeral_pubkey; } //------------------------------------------------------------------------------------------------------------------- -bool verify_external_carrot_janus_protection_receiver(const janus_anchor_t &nominal_anchor, - const input_context_t &input_context, - const crypto::public_key &nominal_address_spend_pubkey, - const crypto::public_key &account_spend_pubkey, - const crypto::secret_key &k_view, - const crypto::x25519_pubkey &enote_ephemeral_pubkey, - payment_id_t &nominal_payment_id_inout) -{ - const bool is_subaddress = nominal_address_spend_pubkey != account_spend_pubkey; - - // make K^j_v', given K^j_s' - crypto::public_key nominal_address_view_pubkey; - if (is_subaddress) - nominal_address_view_pubkey = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(nominal_address_spend_pubkey), - rct::sk2rct(k_view))); - else // cryptonote address - nominal_address_view_pubkey = rct::rct2pk(rct::scalarmultBase(rct::sk2rct(k_view))); - - // if can recompute D_e with pid', then PASS - if (verify_external_carrot_janus_protection(nominal_anchor, - input_context, - nominal_address_spend_pubkey, - nominal_address_view_pubkey, - is_subaddress, - nominal_payment_id_inout, - enote_ephemeral_pubkey)) - return true; - - // if can recompute D_e with null pid, then PASS - nominal_payment_id_inout = null_payment_id; - if (verify_external_carrot_janus_protection(nominal_anchor, - input_context, - nominal_address_spend_pubkey, - nominal_address_view_pubkey, - is_subaddress, - null_payment_id, - enote_ephemeral_pubkey)) - return true; - - // neither D_e recompute attempt passed, so FAIL - return false; -} -//------------------------------------------------------------------------------------------------------------------- -bool verify_special_carrot_janus_protection(const crypto::x25519_pubkey &enote_ephemeral_pubkey, - const input_context_t &input_context, - const crypto::public_key &onetime_address, - const crypto::secret_key &k_view, - const crypto::public_key &account_spend_pubkey, - const janus_anchor_t &nominal_anchor) -{ - // anchor_sp' = H_16(D_e, input_context, Ko, k_v, K_s) - janus_anchor_t nominal_special_anchor; - make_carrot_janus_anchor_special(enote_ephemeral_pubkey, - input_context, - onetime_address, - k_view, - account_spend_pubkey, - nominal_special_anchor); - - // anchor_sp' ?= anchor' - return nominal_special_anchor == nominal_anchor; -} -//------------------------------------------------------------------------------------------------------------------- -bool verify_carrot_janus_protection(const input_context_t &input_context, - const crypto::public_key &onetime_address, - const crypto::secret_key &k_view, - const crypto::public_key &account_spend_pubkey, - const crypto::public_key &nominal_address_spend_pubkey, - const crypto::x25519_pubkey &enote_ephemeral_pubkey, - const janus_anchor_t &nominal_anchor, - payment_id_t &nominal_payment_id_inout) -{ - // try checking for Janus protection, normal external path - if (verify_external_carrot_janus_protection_receiver(nominal_anchor, - input_context, - nominal_address_spend_pubkey, - account_spend_pubkey, - k_view, - enote_ephemeral_pubkey, - nominal_payment_id_inout)) - return true; - - // pid is always null for self-send enotes - nominal_payment_id_inout = null_payment_id; - - // try checking for Janus protection, special path - if (verify_special_carrot_janus_protection(enote_ephemeral_pubkey, - input_context, - onetime_address, - k_view, - account_spend_pubkey, - nominal_anchor)) - return true; - - // neither attempt at checking Janus protection worked - return false; -} -//------------------------------------------------------------------------------------------------------------------- } //namespace carrot diff --git a/src/carrot_core/enote_utils.h b/src/carrot_core/enote_utils.h index 420b114a0..4165f7a13 100644 --- a/src/carrot_core/enote_utils.h +++ b/src/carrot_core/enote_utils.h @@ -1,4 +1,4 @@ -// Copyright (c) 2022, The Monero Project +// Copyright (c) 2024, The Monero Project // // All rights reserved. // @@ -364,7 +364,7 @@ bool try_get_carrot_amount(const crypto::hash &s_sender_receiver, rct::xmr_amount &amount_out, crypto::secret_key &amount_blinding_factor_out); /** - * brief: verify_external_carrot_janus_protection - check normal external enote is Janus safe (i.e. can recompute D_e) + * brief: verify_carrot_external_janus_protection - check normal external enote is Janus safe (i.e. can recompute D_e) * param: nominal_anchor - anchor' * param: input_context - * param: nominal_address_spend_pubkey - K^j_s' @@ -374,67 +374,11 @@ bool try_get_carrot_amount(const crypto::hash &s_sender_receiver, * param: enote_ephemeral_pubkey - D_e * return: true if this normal external enote is safe from Janus attacks */ -bool verify_external_carrot_janus_protection(const janus_anchor_t &nominal_anchor, +bool verify_carrot_external_janus_protection(const janus_anchor_t &nominal_anchor, const input_context_t &input_context, const crypto::public_key &nominal_address_spend_pubkey, const crypto::public_key &nominal_address_view_pubkey, const bool is_subaddress, const payment_id_t nominal_payment_id, const crypto::x25519_pubkey &enote_ephemeral_pubkey); -/** - * brief: verify_external_carrot_janus_protection_receiver - check normal external enote is Janus safe (i.e. can - * recompute D_e), and perhaps set nominal pid to null - * param: nominal_anchor - anchor' - * param: input_context - - * param: nominal_address_spend_pubkey - K^j_s' - * param: account_spend_pubkey - K_s - * param: k_view - k_v - * param: enote_ephemeral_pubkey - D_e - * outparam: nominal_payment_id_inout - pid', first tries recomputing D_e with pid', then sets to null and tries again - * return: true if this normal external enote is safe from Janus attacks - */ -bool verify_external_carrot_janus_protection_receiver(const janus_anchor_t &nominal_anchor, - const input_context_t &input_context, - const crypto::public_key &nominal_address_spend_pubkey, - const crypto::public_key &account_spend_pubkey, - const crypto::secret_key &k_view, - const crypto::x25519_pubkey &enote_ephemeral_pubkey, - payment_id_t &nominal_payment_id_inout); -/** - * brief: verify_special_carrot_janus_protection - check special enote is Janus safe (i.e. can recompute anchor_sp) - * param: enote_ephemeral_pubkey - D_e - * param: input_context - - * param: onetime_address - Ko - * param: k_view - k_v - * param: account_spend_pubkey - K_s - * param: nominal_anchor - anchor' - * return: true if this special enote is safe from Janus attacks - */ -bool verify_special_carrot_janus_protection(const crypto::x25519_pubkey &enote_ephemeral_pubkey, - const input_context_t &input_context, - const crypto::public_key &onetime_address, - const crypto::secret_key &k_view, - const crypto::public_key &account_spend_pubkey, - const janus_anchor_t &nominal_anchor); -/** - * brief: verify_carrot_janus_protection - check whether a received Carrot enote is Janus protected (all paths) - * param: input_context - - * param: onetime_address - Ko - * param: k_view - k_v - * param: account_spend_pubkey - K_s - * param: nominal_address_spend_pubkey - K^j_s' - * param: enote_ephemeral_pubkey - D_e - * param: nominal_anchor - anchor' - * outparam: nominal_payment_id_inout - pass possible pid, set to null if the sender didn't explicitly bind to that pid - * return: true if this received enote is safe from Janus attacks - */ -bool verify_carrot_janus_protection(const input_context_t &input_context, - const crypto::public_key &onetime_address, - const crypto::secret_key &k_view, - const crypto::public_key &account_spend_pubkey, - const crypto::public_key &nominal_address_spend_pubkey, - const crypto::x25519_pubkey &enote_ephemeral_pubkey, - const janus_anchor_t &nominal_anchor, - payment_id_t &nominal_payment_id_inout); - } //namespace carrot diff --git a/src/carrot_core/hash_functions.cpp b/src/carrot_core/hash_functions.cpp index 2b59960c7..8eca353d1 100644 --- a/src/carrot_core/hash_functions.cpp +++ b/src/carrot_core/hash_functions.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2022, The Monero Project +// Copyright (c) 2024, The Monero Project // // All rights reserved. // diff --git a/src/carrot_core/hash_functions.h b/src/carrot_core/hash_functions.h index 6ddc09529..cb6baf830 100644 --- a/src/carrot_core/hash_functions.h +++ b/src/carrot_core/hash_functions.h @@ -1,4 +1,4 @@ -// Copyright (c) 2022, The Monero Project +// Copyright (c) 2024, The Monero Project // // All rights reserved. // diff --git a/src/carrot_core/payment_proposal.cpp b/src/carrot_core/payment_proposal.cpp index 7a0472460..67f73757d 100644 --- a/src/carrot_core/payment_proposal.cpp +++ b/src/carrot_core/payment_proposal.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2022, The Monero Project +// Copyright (c) 2024, The Monero Project // // All rights reserved. // diff --git a/src/carrot_core/payment_proposal.h b/src/carrot_core/payment_proposal.h index 874cc491f..d4250d25a 100644 --- a/src/carrot_core/payment_proposal.h +++ b/src/carrot_core/payment_proposal.h @@ -1,4 +1,4 @@ -// Copyright (c) 2022, The Monero Project +// Copyright (c) 2024, The Monero Project // // All rights reserved. // diff --git a/src/carrot_core/transcript_fixed.h b/src/carrot_core/transcript_fixed.h index 082bbb7fa..8dcf2963e 100644 --- a/src/carrot_core/transcript_fixed.h +++ b/src/carrot_core/transcript_fixed.h @@ -1,4 +1,4 @@ -// Copyright (c) 2022-2024, The Monero Project +// Copyright (c) 2024, The Monero Project // // All rights reserved. // diff --git a/tests/unit_tests/carrot_core.cpp b/tests/unit_tests/carrot_core.cpp index 88817d4ef..9f250511e 100644 --- a/tests/unit_tests/carrot_core.cpp +++ b/tests/unit_tests/carrot_core.cpp @@ -31,6 +31,7 @@ #include "carrot_core/account_secrets.h" #include "carrot_core/address_utils.h" #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" @@ -53,6 +54,12 @@ struct mock_carrot_keys crypto::public_key account_view_pubkey; crypto::public_key main_address_view_pubkey; + view_incoming_key_ram_borrowed_device k_view_dev; + view_balance_secret_ram_borrowed_device s_view_balance_dev; + + mock_carrot_keys(): k_view_dev(k_view), s_view_balance_dev(s_view_balance) + {} + static mock_carrot_keys generate() { mock_carrot_keys k; @@ -183,7 +190,7 @@ TEST(carrot_core, main_address_normal_scan_completeness) const bool scan_success = try_scan_carrot_enote_external(enote, encrypted_payment_id, s_sender_receiver_unctx, - keys.k_view, + keys.k_view_dev, keys.account_spend_pubkey, recovered_sender_extension_g, recovered_sender_extension_t, @@ -263,7 +270,7 @@ TEST(carrot_core, subaddress_normal_scan_completeness) const bool scan_success = try_scan_carrot_enote_external(enote, encrypted_payment_id, s_sender_receiver_unctx, - keys.k_view, + keys.k_view_dev, keys.account_spend_pubkey, recovered_sender_extension_g, recovered_sender_extension_t, @@ -351,7 +358,7 @@ TEST(carrot_core, integrated_address_normal_scan_completeness) const bool scan_success = try_scan_carrot_enote_external(enote, encrypted_payment_id, s_sender_receiver_unctx, - keys.k_view, + keys.k_view_dev, keys.account_spend_pubkey, recovered_sender_extension_g, recovered_sender_extension_t, @@ -429,7 +436,7 @@ TEST(carrot_core, main_address_special_scan_completeness) const bool scan_success = try_scan_carrot_enote_external(enote, std::nullopt, s_sender_receiver_unctx, - keys.k_view, + keys.k_view_dev, keys.account_spend_pubkey, recovered_sender_extension_g, recovered_sender_extension_t, @@ -516,7 +523,7 @@ TEST(carrot_core, subaddress_special_scan_completeness) const bool scan_success = try_scan_carrot_enote_external(enote, std::nullopt, s_sender_receiver_unctx, - keys.k_view, + keys.k_view_dev, keys.account_spend_pubkey, recovered_sender_extension_g, recovered_sender_extension_t, @@ -599,7 +606,7 @@ TEST(carrot_core, main_address_internal_scan_completeness) crypto::secret_key recovered_amount_blinding_factor; CarrotEnoteType recovered_enote_type; const bool scan_success = try_scan_carrot_enote_internal(enote, - keys.s_view_balance, + keys.s_view_balance_dev, recovered_sender_extension_g, recovered_sender_extension_t, recovered_address_spend_pubkey, @@ -674,7 +681,7 @@ TEST(carrot_core, subaddress_internal_scan_completeness) crypto::secret_key recovered_amount_blinding_factor; CarrotEnoteType recovered_enote_type; const bool scan_success = try_scan_carrot_enote_internal(enote, - keys.s_view_balance, + keys.s_view_balance_dev, recovered_sender_extension_g, recovered_sender_extension_t, recovered_address_spend_pubkey, @@ -745,7 +752,7 @@ TEST(carrot_core, main_address_coinbase_scan_completeness) crypto::public_key recovered_address_spend_pubkey; const bool scan_success = try_scan_carrot_coinbase_enote(enote, s_sender_receiver_unctx, - keys.k_view, + keys.k_view_dev, keys.account_spend_pubkey, recovered_sender_extension_g, recovered_sender_extension_t,