diff --git a/src/cryptonote_basic/cryptonote_boost_serialization.h b/src/cryptonote_basic/cryptonote_boost_serialization.h index 41fa0e2..3a89484 100644 --- a/src/cryptonote_basic/cryptonote_boost_serialization.h +++ b/src/cryptonote_basic/cryptonote_boost_serialization.h @@ -423,7 +423,7 @@ namespace boost a & x.p_r; if (x.type == rct::RCTTypeFullProofs) { a & x.pr_proof; - //a & x.sa_proofs; + a & x.sa_proofs; } } @@ -462,7 +462,7 @@ namespace boost a & x.p_r; if (x.type == rct::RCTTypeFullProofs) { a & x.pr_proof; - //a & x.sa_proofs; + a & x.sa_proofs; } //-------------- a & x.p.rangeSigs; diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 3e2dca5..07f5829 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -3619,10 +3619,12 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context } if (hf_version >= HF_VERSION_FULL_PROOFS) { - if (tx.rct_signatures.type != rct::RCTTypeFullProofs) { - MERROR_VER("FullProofs required after v" + std::to_string(HF_VERSION_FULL_PROOFS)); - tvc.m_invalid_output = true; - return false; + if (tx.type == cryptonote::transaction_type::TRANSFER) { + if (tx.rct_signatures.type != rct::RCTTypeFullProofs) { + MERROR_VER("FullProofs required for TRANSFER TXs after v" + std::to_string(HF_VERSION_FULL_PROOFS)); + tvc.m_invalid_output = true; + return false; + } } } diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index ae5ee89..a13d4d0 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -858,6 +858,7 @@ namespace cryptonote //fill outputs size_t output_index = 0; crypto::secret_key x_change = crypto::null_skey; + rct::key key_yF; uint8_t change_index = 0; for(const tx_destination_entry& dst_entr: destinations) { @@ -970,6 +971,12 @@ namespace cryptonote // Push the F point into the TX vector of F points tx.return_address_list.push_back(F); + // Calculate the shared secret yF + if (hf_version >= HF_VERSION_FULL_PROOFS) { + rct::key key_aP = rct::scalarmultKey(rct::pk2rct(P_change), rct::sk2rct(sender_account_keys.m_view_secret_key)); + key_yF = rct::hash_to_scalar(key_aP); + } + // Calculate the encrypted_change_index data for this output struct { char domain_separator[8]; @@ -1209,7 +1216,8 @@ namespace cryptonote rct_config, hwdev, rct::sk2rct(x_change), - change_index + change_index, + key_yF ); else tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, sources[0].real_output, outSk, rct_config, hwdev); // same index assumption diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 9bbdf72..058d7db 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -1098,7 +1098,7 @@ namespace rct { return index; } - std::vector SAProof_Gen(const keyV &pubkeys, const key &x_change, const size_t change_index) { + std::vector SAProof_Gen(const keyV &pubkeys, const key &x_change, const size_t change_index, const key &key_yF) { // Declare a return structure std::vector proofs{}; @@ -1126,9 +1126,10 @@ namespace rct { // Calculate the challenge hash from the commitments plus the pubkeys keyV challenge_keys; - challenge_keys.reserve(pubkeys.size() * 2); + challenge_keys.reserve(pubkeys.size() * 2 + 1); challenge_keys.insert(challenge_keys.end(), commitments.begin(), commitments.end()); challenge_keys.insert(challenge_keys.end(), pubkeys.begin(), pubkeys.end()); + challenge_keys.push_back(key_yF); rct::key c = rct::hash_to_scalar(challenge_keys); sc_reduce32(c.bytes); @@ -1144,8 +1145,8 @@ namespace rct { rct::key z_x; sc_muladd(z_x.bytes, x_val.bytes, c.bytes, scalars[j].bytes); //rct::key z_x = rct::addKeys(scalars[j], rct::scalarmultKey(c, x_val)); - rct::key z_y = scalars[j]; - proofs.push_back({commitments[j], z_x, z_y}); + //rct::key z_y = scalars[j]; + proofs.push_back({commitments[j], z_x, rct::zero()}); } // Return the proof to the caller @@ -1153,18 +1154,19 @@ namespace rct { } - bool SAProof_Ver(const std::vector &proofs, const keyV &pubkeys, const size_t change_index) { + bool SAProof_Ver(const std::vector &proofs, const keyV &pubkeys, const size_t change_index, const key &key_yF) { // Sanity checks CHECK_AND_ASSERT_THROW_MES(proofs.size() == pubkeys.size(), "PRProof_Ver() failed - proof count does not match output count"); CHECK_AND_ASSERT_THROW_MES(change_index < pubkeys.size(), "PRProof_Ver() failed - invalid change index provided"); // Recompute the challenge hash keyV challenge_keys; - challenge_keys.reserve(pubkeys.size() * 2); + challenge_keys.reserve(pubkeys.size() * 2 + 1); for (const auto &proof_entr: proofs) { challenge_keys.push_back(proof_entr.R); } challenge_keys.insert(challenge_keys.end(), pubkeys.begin(), pubkeys.end()); + challenge_keys.push_back(key_yF); rct::key c = rct::hash_to_scalar(challenge_keys); sc_reduce32(c.bytes); @@ -1172,23 +1174,17 @@ namespace rct { const auto &proof = proofs[change_index]; const rct::key &R = proof.R; // Commitment const rct::key &z_x = proof.z1; // z_x value - const rct::key &z_y = proof.z2; // z_y value const rct::key P = pubkeys[change_index]; // Verify the proof for the change output // Recalculate the expected commitment using the formula: z_x * G = R + c * P - rct::key expected_commitment = rct::addKeys(R, rct::scalarmultKey(c, P)); + rct::key expected_commitment = rct::addKeys(R, rct::scalarmultKey(P, c)); // Verify z_x * G matches the expected commitment if (!rct::equalKeys(rct::scalarmultBase(z_x), expected_commitment)) { return false; // Verification failed } - // Verify z_y * G matches the original commitment - if (!rct::equalKeys(rct::scalarmultBase(z_y), R)) { - return false; // Verification failed - } - // All checks passed return true; } @@ -1281,7 +1277,8 @@ namespace rct { const RCTConfig &rct_config, hw::device &hwdev, const key &x_change, - const size_t change_index + const size_t change_index, + const key &key_yF ) { const bool bulletproof_or_plus = rct_config.range_proof_type > RangeProofBorromean; @@ -1451,6 +1448,16 @@ namespace rct { DP(rv.p_r); if (rv.type == RCTTypeFullProofs) rv.pr_proof = PRProof_Gen(difference); + + // Check if spend authority proof is needed (only for TRANSFER TXs) + rv.sa_proofs.clear(); + if (tx_type == cryptonote::transaction_type::TRANSFER && rv.type == rct::RCTTypeFullProofs) { + rv.sa_proofs = SAProof_Gen(destinations, x_change, change_index, key_yF); + //#ifdef DBG + CHECK_AND_ASSERT_THROW_MES(SAProof_Ver(rv.sa_proofs, destinations, change_index, key_yF), "SAProof_Ver() failed on recently created proof"); + //#endif + } + key full_message = get_pre_mlsag_hash(rv,hwdev); for (i = 0 ; i < inamounts.size(); i++) @@ -1468,16 +1475,6 @@ namespace rct { } } - // Check if spend authority proof is needed (only for TRANSFER TXs) - /* - if (tx_type == cryptonote::transaction_type::TRANSFER && rv.type == rct::RCTTypeFullProofs) { - rv.sa_proofs = SAProof_Gen(destinations, x_change, change_index); -#ifdef DBG - CHECK_AND_ASSERT_THROW_MES(SAProof_Ver(rv.sa_proofs, destinations, change_index), "SAProof_Ver() failed on recently created proof"); -#endif - } - */ - return rv; } @@ -1497,7 +1494,8 @@ namespace rct { const RCTConfig &rct_config, hw::device &hwdev, const key &x_change, - const size_t change_index + const size_t change_index, + const key &key_yF ) { std::vector index; index.resize(inPk.size()); @@ -1508,7 +1506,7 @@ namespace rct { mixRing[i].resize(mixin+1); index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin); } - return genRctSimple(message, inSk, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, outamounts, txnFee, mixRing, amount_keys, index, outSk, rct_config, hwdev, x_change, change_index); + return genRctSimple(message, inSk, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, outamounts, txnFee, mixRing, amount_keys, index, outSk, rct_config, hwdev, x_change, change_index, key_yF); } //RingCT protocol diff --git a/src/ringct/rctSigs.h b/src/ringct/rctSigs.h index 38aa1ea..0c6a88b 100644 --- a/src/ringct/rctSigs.h +++ b/src/ringct/rctSigs.h @@ -88,8 +88,8 @@ namespace rct { zk_proof PRProof_Gen(const rct::key &difference); bool PRProof_Ver(const rct::key &C, const zk_proof &proof); - std::vector SAProof_Gen(const keyV &pubkeys, const key &x_change, const size_t change_index); - bool SAProof_Ver(const std::vector &proofs, const keyV &pubkeys, const size_t change_index); + std::vector SAProof_Gen(const keyV &pubkeys, const key &x_change, const size_t change_index, const key &key_yF); + bool SAProof_Ver(const std::vector &proofs, const keyV &pubkeys, const size_t change_index, const key &key_yF); //proveRange and verRange //proveRange gives C, and mask such that \sumCi = C @@ -150,7 +150,8 @@ namespace rct { const RCTConfig &rct_config, hw::device &hwdev, const key &x_change = rct::zero(), - const size_t change_index = 0 + const size_t change_index = 0, + const key &key_yF = rct::zero() ); rctSig genRctSimple( const key & message, @@ -169,7 +170,8 @@ namespace rct { const RCTConfig &rct_config, hw::device &hwdev, const key &x_change = rct::zero(), - const size_t change_index = 0 + const size_t change_index = 0, + const key &key_yF = rct::zero() ); bool verRct(const rctSig & rv, bool semantics); static inline bool verRct(const rctSig & rv) { return verRct(rv, true) && verRct(rv, false); } diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h index 43b3ec8..2b1002f 100644 --- a/src/ringct/rctTypes.h +++ b/src/ringct/rctTypes.h @@ -421,6 +421,7 @@ namespace rct { if (type == RCTTypeFullProofs) { FIELD(pr_proof) + FIELD(sa_proofs) /* uint32_t nsap = sa_proofs.size(); VARINT_FIELD(nsap) @@ -452,7 +453,7 @@ namespace rct { FIELD(p_r) if (type == RCTTypeFullProofs) { FIELD(pr_proof) - //FIELD(sa_proofs) + FIELD(sa_proofs) } END_SERIALIZE() };