Compare commits

...

2 Commits

Author SHA1 Message Date
Some Random Crypto Guy
e2bc467618 fixed key image calculation for return_payment outputs 2025-08-05 21:11:22 +01:00
Some Random Crypto Guy
cb3f1905ed updated SPARC code to support one-way payment channels, ready for Salvium Two smart contracts 2025-08-05 12:27:20 +01:00
6 changed files with 87 additions and 31 deletions

View File

@@ -75,5 +75,6 @@ static constexpr const unsigned int CARROT_MAX_TX_INPUTS = 128;
// SPARC addressing protocol domain separators
static constexpr const unsigned char SPARC_DOMAIN_SEP_RETURN_PUBKEY_ENCRYPTION_MASK[] = "SPARC return pubkey encryption mask";
static constexpr const unsigned char SPARC_DOMAIN_SEP_RETURN_ADDRESS_SCALAR[] = "SPARC return address scalar";
static constexpr const unsigned char SPARC_DOMAIN_SEP_RETURN_INDEX_SCALAR[] = "SPARC return index scalar";
} //namespace carrot

View File

@@ -211,6 +211,17 @@ void make_sparc_return_privkey(const unsigned char s_sender_receiver_unctx[32],
derive_scalar(transcript.data(), transcript.size(), s_sender_receiver_unctx, &return_privkey_out);
}
//-------------------------------------------------------------------------------------------------------------------
void make_sparc_return_index(const unsigned char s_sender_receiver_unctx[32],
const input_context_t &input_context,
const crypto::public_key &onetime_address,
const uint64_t idx,
crypto::secret_key &return_index_out)
{
// k_return = H_32(s_sr || input_context || Ko)
const auto transcript = sp::make_fixed_transcript<SPARC_DOMAIN_SEP_RETURN_INDEX_SCALAR>(input_context, onetime_address, idx);
derive_scalar(transcript.data(), transcript.size(), s_sender_receiver_unctx, &return_index_out);
}
//-------------------------------------------------------------------------------------------------------------------
void make_sparc_return_pubkey_encryption_mask(const unsigned char s_sender_receiver_unctx[32],
const input_context_t &input_context,
const crypto::public_key &onetime_address,
@@ -222,22 +233,33 @@ void make_sparc_return_pubkey_encryption_mask(const unsigned char s_sender_recei
}
//-------------------------------------------------------------------------------------------------------------------
void make_sparc_return_pubkey(const unsigned char s_sender_receiver_unctx[32],
const input_context_t &input_context,
const view_balance_secret_device *s_view_balance_dev,
const crypto::public_key &onetime_address,
encrypted_return_pubkey_t &return_pubkey_out)
const input_context_t &input_context,
const view_balance_secret_device *s_view_balance_dev,
const crypto::public_key &onetime_address,
const uint64_t idx,
encrypted_return_pubkey_t &return_enc_pubkey_out)
{
// K_return = k_return G ^ m_return
// K_return = k_return G + k_idx T
crypto::secret_key k_return;
crypto::public_key return_pub;
encrypted_return_pubkey_t K_return;
encrypted_return_pubkey_t m_return;
crypto::secret_key k_idx = crypto::null_skey;
encrypted_return_pubkey_t return_pub;
s_view_balance_dev->make_internal_return_privkey(input_context, onetime_address, k_return);
crypto::secret_key_to_public_key(k_return, return_pub);
static_assert(sizeof(K_return.bytes) == sizeof(return_pub.data), "Size mismatch");
memcpy(K_return.bytes, return_pub.data, sizeof(encrypted_return_pubkey_t));
make_sparc_return_index(to_bytes(onetime_address), input_context, onetime_address, idx, k_idx);
rct::key K_return;
rct::addKeys2(K_return,
rct::sk2rct(k_return),
rct::sk2rct(k_idx),
rct::pk2rct(crypto::get_T()));
//K_return = rct::scalarmult8(K_return);
if (!rct::isInMainSubgroup(K_return))
throw std::runtime_error("K_return is not in main subgroup");
static_assert(sizeof(K_return.bytes) == sizeof(return_pub.bytes), "Size mismatch");
memcpy(return_pub.bytes, K_return.bytes, sizeof(encrypted_return_pubkey_t));
// return_enc = return_pub ^ m_return
encrypted_return_pubkey_t m_return;
make_sparc_return_pubkey_encryption_mask(s_sender_receiver_unctx, input_context, onetime_address, m_return);
return_pubkey_out = K_return ^ m_return;
return_enc_pubkey_out = return_pub ^ m_return;
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------

View File

@@ -138,6 +138,20 @@ void make_sparc_return_privkey(const unsigned char s_sender_receiver_unctx[32],
const crypto::public_key &onetime_address,
crypto::secret_key &return_privkey_out);
/**
* brief: make_sparc_return_index - return k_idx, given non-secret data
* k_idx = H_32(s_sr || input_context || Ko || idx)
* param: s_sender_receiver_unctx - s_sr
* param: input_context - input_context
* param: onetime_address - Ko
* param: idx
* outparam: return_index_out - k_idx
*/
void make_sparc_return_index(const unsigned char s_sender_receiver_unctx[32],
const input_context_t &input_context,
const crypto::public_key &onetime_address,
const uint64_t idx,
crypto::secret_key &return_index_out);
/**
* brief: make_sparc_return_pubkey_encryption_mask - used for hiding return pubkey
* m_return = H_32(s_sr || input_context || Ko)
* param: s_sender_receiver_unctx - s_sr
@@ -156,13 +170,15 @@ void make_sparc_return_pubkey_encryption_mask(const unsigned char s_sender_recei
* param: input_context - input_context
* param: s_view_balance_dev - s_vb
* param: onetime_address - Ko
* param: idx
* outparam: return_pubkey_mask_out - K_return
*/
void make_sparc_return_pubkey(const unsigned char s_sender_receiver_unctx[32],
const input_context_t &input_context,
const view_balance_secret_device *s_view_balance_dev,
const crypto::public_key &onetime_address,
encrypted_return_pubkey_t &return_pubkey_out);
const input_context_t &input_context,
const view_balance_secret_device *s_view_balance_dev,
const crypto::public_key &onetime_address,
const uint64_t idx,
encrypted_return_pubkey_t &return_pubkey_out);
/**
* brief: make_carrot_input_context_coinbase - input context for a sender-receiver secret (coinbase txs)
* input_context = "C" || IntToBytes256(block_index)

View File

@@ -361,11 +361,11 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
component_out_of_order, "this set contains duplicate onetime addresses");
// assert all K_o lie in prime order subgroup
// for (const RCTOutputEnoteProposal &output_enote_proposal : output_enote_proposals_out)
// {
// CARROT_CHECK_AND_THROW(rct::isInMainSubgroup(rct::pk2rct(output_enote_proposal.enote.onetime_address)),
// invalid_point, "this set contains an invalid onetime address");
// }
for (const RCTOutputEnoteProposal &output_enote_proposal : output_enote_proposals_out)
{
CARROT_CHECK_AND_THROW(rct::isInMainSubgroup(rct::pk2rct(output_enote_proposal.enote.onetime_address)),
invalid_point, "this set contains an invalid onetime address");
}
// assert unique and non-trivial k_a
memcmp_set<crypto::secret_key> amount_blinding_factors;

View File

@@ -208,10 +208,11 @@ static void get_external_output_proposal_parts(const mx25519_pubkey &s_sender_re
// 4. construct the return pubkey
if (s_view_balance_dev != nullptr)
make_sparc_return_pubkey(s_sender_receiver_unctx.data,
input_context,
s_view_balance_dev,
onetime_address_out,
return_pubkey_out);
input_context,
s_view_balance_dev,
onetime_address_out,
0/*idx*/,
return_pubkey_out);
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------

View File

@@ -34,6 +34,11 @@
//local headers
#include "destination.h"
#include "enote_utils.h"
extern "C"
{
#include "crypto/crypto-ops.h"
}
#include "crypto/generators.h"
#include "ringct/rctOps.h"
#include "scan_unsafe.h"
@@ -508,20 +513,31 @@ bool try_scan_carrot_enote_internal_receiver(const CarrotEnoteV1 &enote,
const carrot::input_context_t input_context = carrot::make_carrot_input_context(enote.tx_first_key_image);
account.s_view_balance_dev.make_internal_return_privkey(input_context, output_key, k_return);
// compute K_return = k_return * G
crypto::public_key K_return;
crypto::secret_key_to_public_key(k_return, K_return);
// make k_idx
crypto::secret_key k_idx = crypto::null_skey;
uint64_t idx = 0;
make_sparc_return_index(to_bytes(output_key), input_context, output_key, idx, k_idx);
// compute K_return = k_return * G + k_idx * T
rct::key K_return;
rct::addKeys2(K_return,
rct::sk2rct(k_return),
rct::sk2rct(k_idx),
rct::pk2rct(crypto::get_T()));
//K_return = rct::scalarmult8(K_return);
// compute K_r = K_return + K_o
crypto::public_key K_r = rct::rct2pk(rct::addKeys(rct::pk2rct(K_return), rct::pk2rct(enote.onetime_address)));
crypto::public_key K_r = rct::rct2pk(rct::addKeys(K_return, rct::pk2rct(enote.onetime_address)));
// calculate the key image for the return output
crypto::secret_key sum_g;
sc_add(to_bytes(sum_g), to_bytes(sender_extension_g_out), to_bytes(k_return));
crypto::secret_key sum_t;
sc_add(to_bytes(sum_t), to_bytes(sender_extension_t_out), to_bytes(k_idx));
crypto::key_image key_image = account.derive_key_image(
account.get_keys().m_carrot_account_address.m_spend_public_key,
sum_g,
sender_extension_t_out,
sum_t,
K_r
);
@@ -529,7 +545,7 @@ bool try_scan_carrot_enote_internal_receiver(const CarrotEnoteV1 &enote,
account.try_searching_for_opening_for_onetime_address(
account.get_keys().m_carrot_account_address.m_spend_public_key,
sum_g,
sender_extension_t_out,
sum_t,
x,
y
);