diff --git a/src/blocks/checkpoints.dat b/src/blocks/checkpoints.dat index 20cb921..8ba5bc6 100644 Binary files a/src/blocks/checkpoints.dat and b/src/blocks/checkpoints.dat differ diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 0be78f7..4fe7d91 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1558,16 +1558,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(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(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 outputs_verified; diff --git a/src/multisig/multisig_tx_builder_ringct.cpp b/src/multisig/multisig_tx_builder_ringct.cpp index 5b48a83..18c309f 100644 --- a/src/multisig/multisig_tx_builder_ringct.cpp +++ b/src/multisig/multisig_tx_builder_ringct.cpp @@ -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_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 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; diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index d402133..702758c 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -1383,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); @@ -1390,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); diff --git a/src/ringct/rctSigs.h b/src/ringct/rctSigs.h index 037be68..d5a0e9f 100644 --- a/src/ringct/rctSigs.h +++ b/src/ringct/rctSigs.h @@ -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 diff --git a/src/version.cpp.in b/src/version.cpp.in index 41201df..d56fb66 100644 --- a/src/version.cpp.in +++ b/src/version.cpp.in @@ -1,5 +1,5 @@ #define DEF_SALVIUM_VERSION_TAG "@VERSIONTAG@" -#define DEF_SALVIUM_VERSION "0.7.0-rc3" +#define DEF_SALVIUM_VERSION "0.7.0-rc4" #define DEF_MONERO_VERSION_TAG "release" #define DEF_MONERO_VERSION "0.18.3.3" #define DEF_MONERO_RELEASE_NAME "Zero" diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 313dd7c..f65d381 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2856,6 +2856,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote 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 @@ -2863,6 +2864,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote 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) @@ -2980,7 +2982,8 @@ 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 @@ -2988,6 +2991,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote 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)