Compare commits
14 Commits
v0.7.0-rc2
..
v0.7.2
| Author | SHA1 | Date | |
|---|---|---|---|
| 114297d784 | |||
| 6368aee05f | |||
| 8599cdf95b | |||
| d39f2f180e | |||
| c763febe98 | |||
| cef01372b1 | |||
| e15dbb5db2 | |||
| 82d706aacb | |||
| f3522764a1 | |||
| 0448a6bf9a | |||
| 2ce22c2508 | |||
| 1334bac45a | |||
| e909e3eef1 | |||
| 8c999520d1 |
@@ -109,7 +109,7 @@ jobs:
|
||||
with:
|
||||
name: ${{ matrix.toolchain.name }}
|
||||
path: |
|
||||
/home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/build/${{ matrix.toolchain.host }}/release/bin/salvium-wallet-cli*
|
||||
/home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/build/${{ matrix.toolchain.host }}/release/bin/salvium-wallet-*
|
||||
/home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/build/${{ matrix.toolchain.host }}/release/bin/salviumd*
|
||||
- name: zip daemon & cli
|
||||
run: |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Salvium Zero v0.7.0-rc2
|
||||
# Salvium Zero v0.7.2
|
||||
|
||||
Copyright (c) 2023-2024, Salvium
|
||||
Portions Copyright (c) 2014-2023, The Monero Project
|
||||
|
||||
Binary file not shown.
@@ -220,6 +220,8 @@
|
||||
|
||||
#define HF_VERSION_FULL_PROOFS 3
|
||||
|
||||
#define HF_VERSION_ENFORCE_FULL_PROOFS 4
|
||||
|
||||
#define HF_VERSION_REQUIRE_VIEW_TAGS 255
|
||||
#define HF_VERSION_ENABLE_CONVERT 255
|
||||
#define HF_VERSION_ENABLE_ORACLE 255
|
||||
|
||||
@@ -1498,6 +1498,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
|
||||
case HF_VERSION_BULLETPROOF_PLUS:
|
||||
case HF_VERSION_ENABLE_N_OUTS:
|
||||
case HF_VERSION_FULL_PROOFS:
|
||||
case HF_VERSION_ENFORCE_FULL_PROOFS:
|
||||
if (b.miner_tx.amount_burnt > 0) {
|
||||
CHECK_AND_ASSERT_MES(money_in_use + b.miner_tx.amount_burnt > money_in_use, false, "miner transaction is overflowed by amount_burnt");
|
||||
money_in_use += b.miner_tx.amount_burnt;
|
||||
@@ -1558,16 +1559,19 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
|
||||
if (o.target.type() == typeid(txout_to_key)) {
|
||||
txout_to_key out = boost::get<txout_to_key>(o.target);
|
||||
CHECK_AND_ASSERT_MES(out.unlock_time == CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, false, "Invalid unlock time on protocol_tx output");
|
||||
CHECK_AND_ASSERT_MES(outputs.count(out.key) == 0, false, "Output duplicated in protocol_tx");
|
||||
outputs[out.key] = std::make_tuple(out.asset_type, o.amount, out.unlock_time);
|
||||
} else if (o.target.type() == typeid(txout_to_tagged_key)) {
|
||||
txout_to_tagged_key out = boost::get<txout_to_tagged_key>(o.target);
|
||||
CHECK_AND_ASSERT_MES(out.unlock_time == CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, false, "Invalid unlock time on protocol_tx output");
|
||||
CHECK_AND_ASSERT_MES(outputs.count(out.key) == 0, false, "Output duplicated in protocol_tx");
|
||||
outputs[out.key] = std::make_tuple(out.asset_type, o.amount, out.unlock_time);
|
||||
} else {
|
||||
MERROR("Block at height: " << height << " attempting to add protocol transaction with invalid type " << o.target.type().name());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
CHECK_AND_ASSERT_MES(outputs.size() == b.protocol_tx.vout.size(), false, "Mismatch between vout and outputs for protocol_tx - aborting");
|
||||
|
||||
// Maintain a count of outputs that we have verified
|
||||
std::vector<crypto::public_key> outputs_verified;
|
||||
@@ -3489,9 +3493,9 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
// from v4, forbid invalid pubkeys
|
||||
if (hf_version >= 4) {
|
||||
if (hf_version >= 1) {
|
||||
for (const auto &o: tx.vout) {
|
||||
crypto::public_key output_public_key;
|
||||
if (!get_output_public_key(o, output_public_key)) {
|
||||
@@ -3504,7 +3508,7 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// from v8, allow bulletproofs
|
||||
if (hf_version < 8) {
|
||||
if (tx.version >= 2) {
|
||||
@@ -3603,10 +3607,9 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// from v16, forbid bulletproofs
|
||||
if (hf_version > HF_VERSION_BULLETPROOF_PLUS) {
|
||||
// from v1, forbid bulletproofs
|
||||
if (hf_version >= HF_VERSION_BULLETPROOF_PLUS) {
|
||||
if (tx.version >= 2) {
|
||||
const bool bulletproof = rct::is_rct_bulletproof(tx.rct_signatures.type);
|
||||
if (bulletproof)
|
||||
@@ -3617,11 +3620,19 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if (hf_version >= HF_VERSION_FULL_PROOFS) {
|
||||
if (tx.type == cryptonote::transaction_type::TRANSFER) {
|
||||
// from v4, only allow bulletproofs plus _with_ full proofs on RCT transactions
|
||||
if (hf_version >= HF_VERSION_ENFORCE_FULL_PROOFS) {
|
||||
if (tx.type == cryptonote::transaction_type::TRANSFER || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT) {
|
||||
if (tx.rct_signatures.type != rct::RCTTypeFullProofs) {
|
||||
MERROR_VER("FullProofs required for TRANSFER TXs after v" + std::to_string(HF_VERSION_FULL_PROOFS));
|
||||
MERROR_VER("FullProofs required after v" + std::to_string(HF_VERSION_FULL_PROOFS));
|
||||
tvc.m_invalid_output = true;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (tx.rct_signatures.type != rct::RCTTypeNull) {
|
||||
MERROR_VER("NULL RCT required for coinbase TXs after v" + std::to_string(HF_VERSION_FULL_PROOFS));
|
||||
tvc.m_invalid_output = true;
|
||||
return false;
|
||||
}
|
||||
@@ -3671,6 +3682,15 @@ bool Blockchain::check_tx_type_and_version(const transaction& tx, tx_verificatio
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure CONVERT TXs are disabled until we are ready - belt and braces!
|
||||
if (hf_version < HF_VERSION_ENABLE_CONVERT) {
|
||||
if (tx.type == cryptonote::transaction_type::CONVERT) {
|
||||
MERROR("CONVERT TXs are not permitted prior to v" + std::to_string(HF_VERSION_ENABLE_CONVERT));
|
||||
tvc.m_version_mismatch = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -4031,6 +4051,17 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||
// obviously, the original and simple rct APIs use a mixRing that's indexes
|
||||
// in opposite orders, because it'd be too simple otherwise...
|
||||
const rct::rctSig &rv = tx.rct_signatures;
|
||||
|
||||
// Check that after full proofs are enabled, the RCT version is set to enforce full proofs
|
||||
if (hf_version >= HF_VERSION_ENFORCE_FULL_PROOFS)
|
||||
{
|
||||
if (rv.type != rct::RCTTypeNull && rv.type != rct::RCTTypeFullProofs)
|
||||
{
|
||||
MERROR_VER("Unsupported rct type (full proofs are required): " << rv.type);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (rv.type)
|
||||
{
|
||||
case rct::RCTTypeNull: {
|
||||
@@ -4121,22 +4152,6 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||
MERROR_VER("Unsupported rct type: " << rv.type);
|
||||
return false;
|
||||
}
|
||||
|
||||
// for bulletproofs, check they're only multi-output after v8
|
||||
if (rct::is_rct_bulletproof(rv.type))
|
||||
{
|
||||
if (hf_version < 8)
|
||||
{
|
||||
for (const rct::Bulletproof &proof: rv.p.bulletproofs)
|
||||
{
|
||||
if (proof.V.size() > 1)
|
||||
{
|
||||
MERROR_VER("Multi output bulletproofs are invalid before v8");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -923,6 +923,16 @@ namespace cryptonote
|
||||
if (tx_info[n].tx->version < 2)
|
||||
continue;
|
||||
const rct::rctSig &rv = tx_info[n].tx->rct_signatures;
|
||||
const uint8_t hf_version = m_blockchain_storage.get_current_hard_fork_version();
|
||||
if (hf_version >= HF_VERSION_ENFORCE_FULL_PROOFS) {
|
||||
if (rv.type != rct::RCTTypeNull && rv.type != rct::RCTTypeFullProofs) {
|
||||
MERROR_VER("Invalid RCT type provided");
|
||||
set_semantics_failed(tx_info[n].tx_hash);
|
||||
tx_info[n].tvc.m_verifivation_failed = true;
|
||||
tx_info[n].result = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
switch (rv.type) {
|
||||
case rct::RCTTypeNull:
|
||||
// coinbase should not come here, so we reject for all other types
|
||||
|
||||
@@ -590,6 +590,7 @@ namespace cryptonote
|
||||
case HF_VERSION_BULLETPROOF_PLUS:
|
||||
case HF_VERSION_ENABLE_N_OUTS:
|
||||
case HF_VERSION_FULL_PROOFS:
|
||||
case HF_VERSION_ENFORCE_FULL_PROOFS:
|
||||
// SRCG: subtract 20% that will be rewarded to staking users
|
||||
CHECK_AND_ASSERT_MES(tx.amount_burnt == 0, false, "while creating outs: amount_burnt is nonzero");
|
||||
tx.amount_burnt = amount / 5;
|
||||
|
||||
@@ -36,7 +36,13 @@ const hardfork_t mainnet_hard_forks[] = {
|
||||
{ 1, 1, 0, 1341378000 },
|
||||
|
||||
// version 2 starts from block 89800, which is on or around the 4th of November, 2024. Fork time finalised on 2024-10-21. No fork voting occurs for the v2 fork.
|
||||
{ 2, 89800, 0, 1729518000 },
|
||||
{ 2, 89800, 0, 1729518000 },
|
||||
|
||||
// version 3 starts from block 121100, which is on or around the 19th of December, 2024. Fork time finalised on 2024-12-18. No fork voting occurs for the v3 fork.
|
||||
{ 3, 121100, 0, 1734516900 },
|
||||
|
||||
// version 4 starts from block 121100, which is on or around the 20th of December, 2024. Fork time finalised on 2024-12-19. No fork voting occurs for the v4 fork.
|
||||
{ 4, 121800, 0, 1734607000 },
|
||||
};
|
||||
const size_t num_mainnet_hard_forks = sizeof(mainnet_hard_forks) / sizeof(mainnet_hard_forks[0]);
|
||||
const uint64_t mainnet_hard_fork_version_1_till = ((uint64_t)-1);
|
||||
|
||||
@@ -543,6 +543,9 @@ static bool compute_keys_for_destinations(
|
||||
if (destinations[i].is_change) {
|
||||
found_change = true;
|
||||
change_index = output_index; // Store the change_index - we will need this
|
||||
|
||||
// Calculate the change spend key (x_change)
|
||||
|
||||
}
|
||||
output_index++;
|
||||
}
|
||||
@@ -666,6 +669,8 @@ static void make_new_range_proofs(const int bp_version,
|
||||
sigs.bulletproofs.push_back(rct::bulletproof_PROVE(output_amounts, output_amount_masks));
|
||||
else if (bp_version == 4)
|
||||
sigs.bulletproofs_plus.push_back(rct::bulletproof_plus_PROVE(output_amounts, output_amount_masks));
|
||||
else if (bp_version == 5)
|
||||
sigs.bulletproofs_plus.push_back(rct::bulletproof_plus_PROVE(output_amounts, output_amount_masks));
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
@@ -701,6 +706,12 @@ static bool try_reconstruct_range_proofs(const int bp_version,
|
||||
return false;
|
||||
return rct::bulletproof_plus_VERIFY(reconstructed_sigs.bulletproofs_plus);
|
||||
}
|
||||
else if (bp_version == 5)
|
||||
{
|
||||
if (not try_reconstruct_range_proofs(original_sigs.bulletproofs_plus, reconstructed_sigs.bulletproofs_plus))
|
||||
return false;
|
||||
return rct::bulletproof_plus_VERIFY(reconstructed_sigs.bulletproofs_plus);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -818,7 +829,10 @@ static bool set_tx_rct_signatures(
|
||||
const bool reconstruction,
|
||||
cryptonote::transaction& unsigned_tx,
|
||||
std::vector<CLSAG_context_t>& CLSAG_contexts,
|
||||
rct::keyV& cached_w
|
||||
rct::keyV& cached_w,
|
||||
const uint8_t change_index,
|
||||
const rct::key& x_change,
|
||||
const rct::key& hs_yF
|
||||
)
|
||||
{
|
||||
if (rct_config.bp_version != 3 &&
|
||||
@@ -919,15 +933,38 @@ static bool set_tx_rct_signatures(
|
||||
sc_sub(difference.bytes, sumpouts.bytes, sumouts.bytes);
|
||||
rct::genC(rv.p_r, difference, 0);
|
||||
if (rv.type == rct::RCTTypeFullProofs) {
|
||||
rv.pr_proof = PRProof_Gen(difference);
|
||||
rv.pr_proof = rct::PRProof_Gen(difference);
|
||||
#ifdef DBG
|
||||
CHECK_AND_ASSERT_THROW_MES(rct::PRProof_Ver(rv.p_r, rv.pr_proof), "PRProof_Ver() failed on recently created proof");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
// Check if spend authority proof is needed (only for TRANSFER TXs)
|
||||
if (unsigned_tx.type == cryptonote::transaction_type::TRANSFER && rv.type == rct::RCTTypeFullProofs) {
|
||||
rv.sa_proof = rct::SAProof_Gen(output_public_keys[change_index], x_change, hs_yF);
|
||||
#ifdef DBG
|
||||
CHECK_AND_ASSERT_THROW_MES(rct::SAProof_Ver(rv.sa_proof, output_public_keys[change_index], hs_yF), "SAProof_Ver() failed on recently created proof");
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
}
|
||||
// check balance if reconstructing the tx
|
||||
else {
|
||||
rv.p.pseudoOuts = unsigned_tx.rct_signatures.p.pseudoOuts;
|
||||
rv.pr_proof = unsigned_tx.rct_signatures.pr_proof; // should verify this during reconstruction
|
||||
rv.sa_proof = unsigned_tx.rct_signatures.sa_proof; // should verify this during reconstruction
|
||||
rv.p_r = unsigned_tx.rct_signatures.p_r;
|
||||
if (rv.type == rct::RCTTypeFullProofs) {
|
||||
if (!rct::PRProof_Ver(unsigned_tx.rct_signatures.p_r, unsigned_tx.rct_signatures.pr_proof))
|
||||
return false;
|
||||
rv.p_r = unsigned_tx.rct_signatures.p_r;
|
||||
rv.pr_proof = unsigned_tx.rct_signatures.pr_proof;
|
||||
/*
|
||||
if (!rct::SAProof_Ver(unsigned_tx.rct_signatures.sa_proof, output_public_keys[change_index], hs_yF))
|
||||
return false;
|
||||
rv.sa_proof = unsigned_tx.rct_signatures.sa_proof; // should verify this during reconstruction
|
||||
*/
|
||||
} else {
|
||||
rv.p_r = unsigned_tx.rct_signatures.p_r;
|
||||
}
|
||||
if (num_sources != rv.p.pseudoOuts.size())
|
||||
return false;
|
||||
rct::key balance_accumulator = rct::scalarmultH(rct::d2h(fee));
|
||||
@@ -1172,6 +1209,8 @@ bool tx_builder_ringct_t::init(
|
||||
// Check that the change element was found
|
||||
if (!found_change)
|
||||
return false;
|
||||
|
||||
//
|
||||
|
||||
// add inputs to tx
|
||||
set_tx_inputs(sources, unsigned_tx);
|
||||
@@ -1186,6 +1225,8 @@ bool tx_builder_ringct_t::init(
|
||||
if (not set_tx_outputs_result)
|
||||
return false;
|
||||
|
||||
rct::key hs_yF;
|
||||
rct::key x_change;
|
||||
if (hf_version >= HF_VERSION_ENABLE_N_OUTS && unsigned_tx.type == cryptonote::transaction_type::TRANSFER) {
|
||||
|
||||
// Get the output public key for the change output
|
||||
@@ -1221,6 +1262,7 @@ bool tx_builder_ringct_t::init(
|
||||
rct::key key_F = rct::scalarmultKey(key_aP_change, key_inv_y);
|
||||
rct::key key_verify = rct::scalarmultKey(key_F, key_y);
|
||||
CHECK_AND_ASSERT_MES(key_verify == key_aP_change, false, "at get_return_address: failed to verify invert() function with smK() approach");
|
||||
hs_yF = rct::hash_to_scalar(key_verify);
|
||||
|
||||
// Push the F point into the TX vector of F points
|
||||
if (not reconstruction)
|
||||
@@ -1241,6 +1283,38 @@ bool tx_builder_ringct_t::init(
|
||||
unsigned_tx.return_address_change_mask.push_back(eci_data);
|
||||
}
|
||||
|
||||
if (hf_version >= HF_VERSION_FULL_PROOFS) {
|
||||
|
||||
// Get the secret spend key for the change element
|
||||
crypto::secret_key spend_skey = crypto::null_skey;
|
||||
for (const auto &multisig_key : account_keys.m_multisig_keys) {
|
||||
sc_add((unsigned char*)spend_skey.data,
|
||||
(const unsigned char*)multisig_key.data,
|
||||
(const unsigned char*)spend_skey.data);
|
||||
}
|
||||
|
||||
// Calculate z_i (the shared secret between sender and ourselves for the original TX)
|
||||
crypto::public_key txkey_pub = crypto::null_pkey; // R
|
||||
const std::vector<crypto::public_key> in_additional_tx_pub_keys = cryptonote::get_additional_tx_pub_keys_from_extra(unsigned_tx);
|
||||
if (in_additional_tx_pub_keys.size() != 0) {
|
||||
CHECK_AND_ASSERT_MES(in_additional_tx_pub_keys.size() == unsigned_tx.vout.size(), false, "incorrect number of additional TX pubkeys in origin TX for return_payment");
|
||||
txkey_pub = in_additional_tx_pub_keys[change_index];
|
||||
} else {
|
||||
txkey_pub = cryptonote::get_tx_pub_key_from_extra(unsigned_tx);
|
||||
}
|
||||
|
||||
// Obtain a separate key_derivation for the P_change output
|
||||
// (using the TX public key and the sender's private view key)
|
||||
hw::device &hwdev = account_keys.get_device();
|
||||
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
|
||||
CHECK_AND_ASSERT_MES(hwdev.generate_key_derivation(txkey_pub, account_keys.m_view_secret_key, derivation), false, "Failed to generate key_derivation for P_change");
|
||||
|
||||
// Calculate the secret spend key "x_change" for the P_change output
|
||||
crypto::secret_key s_change = crypto::null_skey;
|
||||
CHECK_AND_ASSERT_MES(hwdev.derive_secret_key(derivation, change_index, spend_skey, s_change), false, "Failed to derive secret key for P_change");
|
||||
x_change = rct::sk2rct(s_change);
|
||||
}
|
||||
|
||||
} else if (unsigned_tx.type == cryptonote::transaction_type::TRANSFER || unsigned_tx.type == cryptonote::transaction_type::STAKE) {
|
||||
|
||||
// Get the tx public key
|
||||
@@ -1253,7 +1327,7 @@ bool tx_builder_ringct_t::init(
|
||||
|
||||
// prepare input signatures
|
||||
if (not set_tx_rct_signatures(fee, sources, destination_amounts, input_secret_keys, output_public_keys, output_amount_secret_keys,
|
||||
rct_config, reconstruction, unsigned_tx, CLSAG_contexts, cached_w))
|
||||
rct_config, reconstruction, unsigned_tx, CLSAG_contexts, cached_w, change_index, x_change, hs_yF))
|
||||
return false;
|
||||
|
||||
initialized = true;
|
||||
|
||||
+13
-49
@@ -522,33 +522,6 @@ namespace rct {
|
||||
return sc_isnonzero(c.bytes) == 0;
|
||||
}
|
||||
|
||||
|
||||
// Optimized function to hash a vector of keys into a scalar
|
||||
rct::key my_hash_to_scalar(std::vector<rct::key>& keys) {
|
||||
|
||||
// Create a fixed-size buffer large enough to hold all keys and a domain separator
|
||||
size_t total_size = keys.size() * sizeof(rct::key) + sizeof("ZKP") - 1;
|
||||
std::vector<uint8_t> data(total_size);
|
||||
|
||||
// Copy the keys into the buffer
|
||||
size_t offset = 0;
|
||||
for (const auto& key : keys) {
|
||||
std::memcpy(data.data() + offset, key.bytes, sizeof(rct::key));
|
||||
offset += sizeof(rct::key);
|
||||
}
|
||||
|
||||
// Add the domain separator "ZKP" at the end of the buffer
|
||||
const char* domain_separator = "ZKP";
|
||||
std::memcpy(data.data() + offset, domain_separator, sizeof("ZKP") - 1);
|
||||
|
||||
// Hash the concatenated data into a fixed-size hash
|
||||
rct::key hash_output;
|
||||
keccak((const uint8_t *)data.data(), total_size, hash_output.bytes, sizeof(rct::key));
|
||||
sc_reduce32(hash_output.bytes); // Reduce to valid scalar
|
||||
|
||||
return hash_output;
|
||||
}
|
||||
|
||||
zk_proof PRProof_Gen(const rct::key &difference) {
|
||||
zk_proof proof;
|
||||
|
||||
@@ -565,7 +538,6 @@ namespace rct {
|
||||
// Calculate challenge c = H_p(R)
|
||||
std::vector<rct::key> keys{proof.R, comm_diff};
|
||||
rct::key c = rct::hash_to_scalar(keys);
|
||||
sc_reduce32(c.bytes);
|
||||
|
||||
// Calculate response z = r + c * difference
|
||||
sc_muladd(proof.z1.bytes, difference.bytes, c.bytes, r.bytes);
|
||||
@@ -1100,27 +1072,22 @@ namespace rct {
|
||||
|
||||
zk_proof SAProof_Gen(const key &P, const key &x_change, const key &key_yF) {
|
||||
|
||||
// Declare a return structure
|
||||
zk_proof proof{};
|
||||
proof.z2 = rct::zero();
|
||||
|
||||
// Sanity checks
|
||||
// Sanity checks for inputs
|
||||
CHECK_AND_ASSERT_THROW_MES(!rct::equalKeys(P, rct::zero()), "SAProof_Gen() failed - invalid public key provided");
|
||||
CHECK_AND_ASSERT_THROW_MES(!rct::equalKeys(x_change, rct::zero()), "SAProof_Gen() failed - invalid x_change key provided");
|
||||
CHECK_AND_ASSERT_THROW_MES(!rct::equalKeys(key_yF, rct::zero()), "SAProof_Gen() failed - invalid shared secret key provided");
|
||||
|
||||
// Declare a return structure
|
||||
zk_proof proof{};
|
||||
proof.z2 = rct::zero();
|
||||
|
||||
// Calculate a random r value and calculate a commitment R for it
|
||||
rct::key r = rct::skGen();
|
||||
proof.R = rct::scalarmultBase(r);
|
||||
|
||||
// Calculate the challenge hash from the commitments plus the pubkeys
|
||||
keyV challenge_keys;
|
||||
challenge_keys.reserve(3);
|
||||
challenge_keys.push_back(proof.R);
|
||||
challenge_keys.push_back(P);
|
||||
challenge_keys.push_back(key_yF);
|
||||
// Calculate the challenge hash from the commitment plus the pubkey plus the shared secret
|
||||
keyV challenge_keys{proof.R, P, key_yF};
|
||||
rct::key c = rct::hash_to_scalar(challenge_keys);
|
||||
sc_reduce32(c.bytes);
|
||||
|
||||
rct::key z_x;
|
||||
sc_muladd(z_x.bytes, x_change.bytes, c.bytes, r.bytes);
|
||||
@@ -1132,18 +1099,13 @@ namespace rct {
|
||||
|
||||
bool SAProof_Ver(const zk_proof &proof, const key &P, const key &key_yF) {
|
||||
|
||||
// Sanity checks
|
||||
CHECK_AND_ASSERT_THROW_MES(!rct::equalKeys(P, rct::zero()), "SAProof_Gen() failed - invalid public key provided");
|
||||
CHECK_AND_ASSERT_THROW_MES(!rct::equalKeys(key_yF, rct::zero()), "SAProof_Gen() failed - invalid shared secret key provided");
|
||||
// Sanity checks for inputs
|
||||
CHECK_AND_ASSERT_THROW_MES(!rct::equalKeys(P, rct::zero()), "SAProof_Ver() failed - invalid public key provided");
|
||||
CHECK_AND_ASSERT_THROW_MES(!rct::equalKeys(key_yF, rct::zero()), "SAProof_Ver() failed - invalid shared secret key provided");
|
||||
|
||||
// Recompute the challenge hash
|
||||
keyV challenge_keys;
|
||||
challenge_keys.reserve(3);
|
||||
challenge_keys.push_back(proof.R);
|
||||
challenge_keys.push_back(P);
|
||||
challenge_keys.push_back(key_yF);
|
||||
keyV challenge_keys{proof.R, P, key_yF};
|
||||
rct::key c = rct::hash_to_scalar(challenge_keys);
|
||||
sc_reduce32(c.bytes);
|
||||
|
||||
// Recalculate the expected commitment using the formula: z_x * G = R + c * P
|
||||
rct::key expected_commitment = rct::addKeys(proof.R, rct::scalarmultKey(P, c));
|
||||
@@ -1421,6 +1383,7 @@ namespace rct {
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
// Check if spend authority proof is needed (only for TRANSFER TXs)
|
||||
if (tx_type == cryptonote::transaction_type::TRANSFER && rv.type == rct::RCTTypeFullProofs) {
|
||||
rv.sa_proof = SAProof_Gen(destinations[change_index], x_change, key_yF);
|
||||
@@ -1428,6 +1391,7 @@ namespace rct {
|
||||
CHECK_AND_ASSERT_THROW_MES(SAProof_Ver(rv.sa_proof, destinations[change_index], key_yF), "SAProof_Ver() failed on recently created proof");
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
|
||||
key full_message = get_pre_mlsag_hash(rv,hwdev);
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace rct {
|
||||
zk_proof PRProof_Gen(const rct::key &difference);
|
||||
bool PRProof_Ver(const rct::key &C, const zk_proof &proof);
|
||||
|
||||
zk_proof SAProof_Gen(const keyV &P, const key &x_change, const key &key_yF);
|
||||
zk_proof SAProof_Gen(const key &P, const key &x_change, const key &key_yF);
|
||||
bool SAProof_Ver(const zk_proof &proof, const key &P, const key &key_yF);
|
||||
|
||||
//proveRange and verRange
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#define DEF_SALVIUM_VERSION_TAG "@VERSIONTAG@"
|
||||
#define DEF_SALVIUM_VERSION "0.7.0-rc2"
|
||||
#define DEF_SALVIUM_VERSION "0.7.2"
|
||||
#define DEF_MONERO_VERSION_TAG "release"
|
||||
#define DEF_MONERO_VERSION "0.18.3.3"
|
||||
#define DEF_MONERO_RELEASE_NAME "Zero"
|
||||
|
||||
+93
-1
@@ -2242,7 +2242,7 @@ void wallet2::scan_output(const cryptonote::transaction &tx, bool miner_tx, cons
|
||||
*/
|
||||
// Populate the unlock_time
|
||||
THROW_WALLET_EXCEPTION_IF(!cryptonote::get_output_unlock_time(tx.vout[i], tx_scan_info.unlock_time), error::wallet_internal_error, "failed to get output unlock_time");
|
||||
|
||||
|
||||
outs.push_back(i);
|
||||
THROW_WALLET_EXCEPTION_IF(tx_money_got_in_outs[tx_scan_info.received->index][tx_scan_info.asset_type] >= std::numeric_limits<uint64_t>::max() - tx_scan_info.money_transfered,
|
||||
error::wallet_internal_error, "Overflow in received amounts");
|
||||
@@ -2481,6 +2481,77 @@ bool wallet2::get_yield_summary_info(uint64_t &total_burnt,
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::verify_spend_authority_proof(const cryptonote::transaction &tx, const size_t i, const tx_scan_info_t &tx_scan_info)
|
||||
{
|
||||
// Sanity checks
|
||||
if (tx.type != cryptonote::transaction_type::TRANSFER) return true;
|
||||
if (tx.version < TRANSACTION_VERSION_N_OUTS) return true;
|
||||
if (tx.rct_signatures.type != rct::RCTTypeFullProofs) return true;
|
||||
|
||||
// To verify the spend authority proof, we need to know the y value to process the F value
|
||||
ec_scalar y;
|
||||
|
||||
// Get P_change from the TX
|
||||
crypto::public_key P_change = crypto::null_pkey;
|
||||
|
||||
// Calculate z_i (the shared secret between sender and ourselves for the original TX)
|
||||
crypto::public_key txkey_pub = null_pkey; // R
|
||||
const std::vector<crypto::public_key> in_additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(tx);
|
||||
if (in_additional_tx_pub_keys.size() != 0) {
|
||||
THROW_WALLET_EXCEPTION_IF(in_additional_tx_pub_keys.size() != tx.vout.size(),
|
||||
error::wallet_internal_error,
|
||||
tr("at verify_spend_authority_proof(): incorrect number of additional TX pubkeys in TX"));
|
||||
txkey_pub = in_additional_tx_pub_keys[i];
|
||||
} else {
|
||||
txkey_pub = get_tx_pub_key_from_extra(tx);
|
||||
}
|
||||
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
|
||||
THROW_WALLET_EXCEPTION_IF(!generate_key_derivation(txkey_pub, m_account.get_keys().m_view_secret_key, derivation),
|
||||
error::wallet_internal_error,
|
||||
tr("at verify_spend_authority_proof(): failed to generate_key_derivation"));
|
||||
crypto::secret_key z_i;
|
||||
derivation_to_scalar(derivation, i, z_i);
|
||||
|
||||
// Calculate the y value for return_payment support
|
||||
struct {
|
||||
char domain_separator[8];
|
||||
rct::key amount_key;
|
||||
} buf;
|
||||
std::memset(buf.domain_separator, 0x0, sizeof(buf.domain_separator));
|
||||
std::strncpy(buf.domain_separator, "RETURN", 7);
|
||||
buf.amount_key = rct::sk2rct(z_i);
|
||||
crypto::hash_to_scalar(&buf, sizeof(buf), y);
|
||||
|
||||
// The change_index needs decoding too
|
||||
uint8_t eci_data = tx.return_address_change_mask[i];
|
||||
|
||||
// Calculate the encrypted_change_index data for this output
|
||||
std::memset(buf.domain_separator, 0x0, sizeof(buf.domain_separator));
|
||||
std::strncpy(buf.domain_separator, "CHG_IDX", 8);
|
||||
crypto::secret_key eci_out;
|
||||
keccak((uint8_t *)&buf, sizeof(buf), (uint8_t*)&eci_out, sizeof(eci_out));
|
||||
uint8_t change_index = eci_data ^ eci_out.data[0];
|
||||
THROW_WALLET_EXCEPTION_IF(change_index >= tx.vout.size(), error::wallet_internal_error, tr("at verify_spend_authority_proof(): invalid change_index calculated"));
|
||||
|
||||
// Now we know the index, we can get P_change
|
||||
THROW_WALLET_EXCEPTION_IF(!cryptonote::get_output_public_key(tx.vout[change_index], P_change), error::wallet_internal_error, tr("at verify_spend_authority_proof(): failed to get P_change"));
|
||||
rct::key key_P_change = rct::pk2rct(P_change);
|
||||
|
||||
// Calculate the shared secret yF
|
||||
rct::key key_y = (rct::key&)(y);
|
||||
rct::key key_F = (rct::key&)(tx.return_address_list[i]);
|
||||
rct::key key_yF = rct::scalarmultKey(key_F, key_y);
|
||||
rct::key hs_yF = rct::hash_to_scalar(key_yF);
|
||||
|
||||
// Now we can verify the proof itself
|
||||
if (!rct::SAProof_Ver(tx.rct_signatures.sa_proof, key_P_change, hs_yF)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return success to caller
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, const std::vector<uint64_t> &asset_type_output_indices, uint64_t height, uint8_t block_version, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache, bool ignore_callbacks)
|
||||
{
|
||||
PERF_TIMER(process_new_transaction);
|
||||
@@ -2784,6 +2855,17 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||
if (m_multisig_rescan_info && m_multisig_rescan_info->front().size() >= m_transfers.size())
|
||||
update_multisig_rescan_info(*m_multisig_rescan_k, *m_multisig_rescan_info, m_transfers.size() - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
// Verify the spend authority proof
|
||||
if (!verify_spend_authority_proof(tx, o, tx_scan_info[o])) {
|
||||
// Freeze the output
|
||||
LOG_ERROR("Spend authority proof for TX: " << txid << " failed verification. The output has been frozen.");
|
||||
LOG_ERROR("Please review the transaction and verify that the sender is someone you trust before thawing this payment.");
|
||||
td.m_frozen = true;
|
||||
}
|
||||
*/
|
||||
|
||||
LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid);
|
||||
if (!ignore_callbacks && 0 != m_callback)
|
||||
m_callback->on_money_received(height, txid, tx, td.m_amount, td.asset_type, 0, td.m_subaddr_index, spends_one_of_ours(tx), td.m_tx.unlock_time, td.m_td_origin_idx);
|
||||
@@ -2900,6 +2982,16 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||
}
|
||||
THROW_WALLET_EXCEPTION_IF(td.get_public_key() != tx_scan_info[o].in_ephemeral.pub, error::wallet_internal_error, "Inconsistent public keys");
|
||||
THROW_WALLET_EXCEPTION_IF(td.m_spent, error::wallet_internal_error, "Inconsistent spent status");
|
||||
|
||||
/*
|
||||
// Verify the spend authority proof
|
||||
if (!verify_spend_authority_proof(tx, o, tx_scan_info[o])) {
|
||||
// Freeze the output
|
||||
LOG_ERROR("Spend authority proof for TX: " << txid << " failed verification. The output has been frozen.");
|
||||
LOG_ERROR("Please review the transaction and verify that the sender is someone you trust before thawing this payment.");
|
||||
td.m_frozen = true;
|
||||
}
|
||||
*/
|
||||
|
||||
LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid);
|
||||
if (!ignore_callbacks && 0 != m_callback)
|
||||
|
||||
@@ -1191,6 +1191,8 @@ private:
|
||||
|
||||
std::vector<cryptonote::public_node> get_public_nodes(bool white_only = true);
|
||||
|
||||
bool verify_spend_authority_proof(const cryptonote::transaction &tx, const size_t i, const tx_scan_info_t &tx_scan_info);
|
||||
|
||||
template <class t_archive>
|
||||
inline void serialize(t_archive &a, const unsigned int ver)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user