mirror of
https://codeberg.org/anoncontributorxmr/monero.git
synced 2024-11-30 11:13:13 +00:00
rct: split rct checks between semantics and other
Semantics can be checked early
This commit is contained in:
parent
2806842200
commit
ba3968f6ce
4 changed files with 149 additions and 85 deletions
|
@ -2333,10 +2333,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
|
||||||
CHECK_AND_ASSERT_MES(false, false, "Unsupported rct tx type: " + boost::lexical_cast<std::string>(rv.type));
|
CHECK_AND_ASSERT_MES(false, false, "Unsupported rct tx type: " + boost::lexical_cast<std::string>(rv.type));
|
||||||
}
|
}
|
||||||
|
|
||||||
// outPk
|
// outPk was already done by handle_incoming_tx
|
||||||
CHECK_AND_ASSERT_MES(rv.outPk.size() == tx.vout.size(), false, "Bad outPk size");
|
|
||||||
for (size_t n = 0; n < tx.rct_signatures.outPk.size(); ++n)
|
|
||||||
rv.outPk[n].dest = rct::pk2rct(boost::get<txout_to_key>(tx.vout[n].target).key);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2641,7 +2638,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rct::verRctSimple(rv))
|
if (!rct::verRctSimple(rv, false))
|
||||||
{
|
{
|
||||||
LOG_PRINT_L1("Failed to check ringct signatures!");
|
LOG_PRINT_L1("Failed to check ringct signatures!");
|
||||||
return false;
|
return false;
|
||||||
|
@ -2699,7 +2696,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rct::verRct(rv))
|
if (!rct::verRct(rv, false))
|
||||||
{
|
{
|
||||||
LOG_PRINT_L1("Failed to check ringct signatures!");
|
LOG_PRINT_L1("Failed to check ringct signatures!");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -49,6 +49,7 @@ using namespace epee;
|
||||||
#if defined(BERKELEY_DB)
|
#if defined(BERKELEY_DB)
|
||||||
#include "blockchain_db/berkeleydb/db_bdb.h"
|
#include "blockchain_db/berkeleydb/db_bdb.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "ringct/rctSigs.h"
|
||||||
|
|
||||||
DISABLE_VS_WARNINGS(4355)
|
DISABLE_VS_WARNINGS(4355)
|
||||||
|
|
||||||
|
@ -494,6 +495,22 @@ namespace cryptonote
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// resolve outPk references in rct txes
|
||||||
|
// outPk aren't the only thing that need resolving for a fully resolved tx,
|
||||||
|
// but outPk (1) are needed now to check range proof semantics, and
|
||||||
|
// (2) do not need access to the blockchain to find data
|
||||||
|
if (tx.version >= 2)
|
||||||
|
{
|
||||||
|
rct::rctSig &rv = tx.rct_signatures;
|
||||||
|
if (rv.outPk.size() != tx.vout.size())
|
||||||
|
{
|
||||||
|
LOG_PRINT_L1("WRONG TRANSACTION BLOB, Bad outPk size in tx " << tx_hash << ", rejected");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (size_t n = 0; n < tx.rct_signatures.outPk.size(); ++n)
|
||||||
|
rv.outPk[n].dest = rct::pk2rct(boost::get<txout_to_key>(tx.vout[n].target).key);
|
||||||
|
}
|
||||||
|
|
||||||
if(!check_tx_semantic(tx, keeped_by_block))
|
if(!check_tx_semantic(tx, keeped_by_block))
|
||||||
{
|
{
|
||||||
LOG_PRINT_L1("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " semantic, rejected");
|
LOG_PRINT_L1("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " semantic, rejected");
|
||||||
|
@ -584,6 +601,33 @@ namespace cryptonote
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tx.version >= 2)
|
||||||
|
{
|
||||||
|
const rct::rctSig &rv = tx.rct_signatures;
|
||||||
|
switch (rv.type) {
|
||||||
|
case rct::RCTTypeNull:
|
||||||
|
// coinbase should not come here, so we reject for all other types
|
||||||
|
LOG_PRINT_RED_L1("Unexpected Null rctSig type");
|
||||||
|
return false;
|
||||||
|
case rct::RCTTypeSimple:
|
||||||
|
if (!rct::verRctSimple(rv, true))
|
||||||
|
{
|
||||||
|
LOG_PRINT_RED_L1("rct signature semantics check failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case rct::RCTTypeFull:
|
||||||
|
if (!rct::verRct(rv, true))
|
||||||
|
{
|
||||||
|
LOG_PRINT_RED_L1("rct signature semantics check failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_PRINT_RED_L1("Unknown rct type: " << rv.type);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -710,43 +710,54 @@ namespace rct {
|
||||||
//decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1)
|
//decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1)
|
||||||
// uses the attached ecdh info to find the amounts represented by each output commitment
|
// uses the attached ecdh info to find the amounts represented by each output commitment
|
||||||
// must know the destination private key to find the correct amount, else will return a random number
|
// must know the destination private key to find the correct amount, else will return a random number
|
||||||
bool verRct(const rctSig & rv) {
|
bool verRct(const rctSig & rv, bool semantics) {
|
||||||
PERF_TIMER(verRct);
|
PERF_TIMER(verRct);
|
||||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "verRct called on non-full rctSig");
|
CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "verRct called on non-full rctSig");
|
||||||
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs");
|
if (semantics)
|
||||||
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo");
|
{
|
||||||
CHECK_AND_ASSERT_MES(rv.p.MGs.size() == 1, false, "full rctSig has not one MG");
|
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs");
|
||||||
|
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo");
|
||||||
|
CHECK_AND_ASSERT_MES(rv.p.MGs.size() == 1, false, "full rctSig has not one MG");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// semantics check is early, we don't have the MGs resolved yet
|
||||||
|
}
|
||||||
|
|
||||||
// some rct ops can throw
|
// some rct ops can throw
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
std::deque<bool> results(rv.outPk.size(), false);
|
if (semantics) {
|
||||||
tools::thread_group threadpool(tools::thread_group::optimal_with_max(rv.outPk.size()));
|
std::deque<bool> results(rv.outPk.size(), false);
|
||||||
|
tools::thread_group threadpool(tools::thread_group::optimal_with_max(rv.outPk.size()));
|
||||||
|
|
||||||
tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
|
tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
|
||||||
DP("range proofs verified?");
|
DP("range proofs verified?");
|
||||||
for (size_t i = 0; i < rv.outPk.size(); i++) {
|
for (size_t i = 0; i < rv.outPk.size(); i++) {
|
||||||
region.run([&, i] {
|
region.run([&, i] {
|
||||||
results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
|
results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
for (size_t i = 0; i < rv.outPk.size(); ++i) {
|
for (size_t i = 0; i < rv.outPk.size(); ++i) {
|
||||||
if (!results[i]) {
|
if (!results[i]) {
|
||||||
LOG_PRINT_L1("Range proof verified failed for output " << i);
|
LOG_PRINT_L1("Range proof verified failed for output " << i);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//compute txn fee
|
if (!semantics) {
|
||||||
key txnFeeKey = scalarmultH(d2h(rv.txnFee));
|
//compute txn fee
|
||||||
bool mgVerd = verRctMG(rv.p.MGs[0], rv.mixRing, rv.outPk, txnFeeKey, get_pre_mlsag_hash(rv));
|
key txnFeeKey = scalarmultH(d2h(rv.txnFee));
|
||||||
DP("mg sig verified?");
|
bool mgVerd = verRctMG(rv.p.MGs[0], rv.mixRing, rv.outPk, txnFeeKey, get_pre_mlsag_hash(rv));
|
||||||
DP(mgVerd);
|
DP("mg sig verified?");
|
||||||
if (!mgVerd) {
|
DP(mgVerd);
|
||||||
LOG_PRINT_L1("MG signature verification failed");
|
if (!mgVerd) {
|
||||||
return false;
|
LOG_PRINT_L1("MG signature verification failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -759,76 +770,86 @@ namespace rct {
|
||||||
|
|
||||||
//ver RingCT simple
|
//ver RingCT simple
|
||||||
//assumes only post-rct style inputs (at least for max anonymity)
|
//assumes only post-rct style inputs (at least for max anonymity)
|
||||||
bool verRctSimple(const rctSig & rv) {
|
bool verRctSimple(const rctSig & rv, bool semantics) {
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
PERF_TIMER(verRctSimple);
|
PERF_TIMER(verRctSimple);
|
||||||
|
|
||||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, false, "verRctSimple called on non simple rctSig");
|
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, false, "verRctSimple called on non simple rctSig");
|
||||||
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs");
|
if (semantics)
|
||||||
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo");
|
{
|
||||||
CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.p.MGs.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.p.MGs");
|
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs");
|
||||||
CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.pseudoOuts and mixRing");
|
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo");
|
||||||
|
CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.p.MGs.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.p.MGs");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// semantics check is early, and mixRing/MGs aren't resolved yet
|
||||||
|
CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.pseudoOuts and mixRing");
|
||||||
|
}
|
||||||
|
|
||||||
const size_t threads = std::max(rv.outPk.size(), rv.mixRing.size());
|
const size_t threads = std::max(rv.outPk.size(), rv.mixRing.size());
|
||||||
|
|
||||||
std::deque<bool> results(threads);
|
std::deque<bool> results(threads);
|
||||||
tools::thread_group threadpool(tools::thread_group::optimal_with_max(threads));
|
tools::thread_group threadpool(tools::thread_group::optimal_with_max(threads));
|
||||||
|
|
||||||
results.clear();
|
if (semantics) {
|
||||||
results.resize(rv.outPk.size());
|
results.clear();
|
||||||
tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
|
results.resize(rv.outPk.size());
|
||||||
|
tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
|
||||||
|
for (size_t i = 0; i < rv.outPk.size(); i++) {
|
||||||
|
region.run([&, i] {
|
||||||
|
results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (size_t i = 0; i < results.size(); ++i) {
|
||||||
|
if (!results[i]) {
|
||||||
|
LOG_PRINT_L1("Range proof verified failed for output " << i);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
key sumOutpks = identity();
|
||||||
for (size_t i = 0; i < rv.outPk.size(); i++) {
|
for (size_t i = 0; i < rv.outPk.size(); i++) {
|
||||||
region.run([&, i] {
|
addKeys(sumOutpks, sumOutpks, rv.outPk[i].mask);
|
||||||
results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
DP(sumOutpks);
|
||||||
|
key txnFeeKey = scalarmultH(d2h(rv.txnFee));
|
||||||
|
addKeys(sumOutpks, txnFeeKey, sumOutpks);
|
||||||
|
|
||||||
for (size_t i = 0; i < results.size(); ++i) {
|
key sumPseudoOuts = identity();
|
||||||
if (!results[i]) {
|
for (size_t i = 0 ; i < rv.pseudoOuts.size() ; i++) {
|
||||||
LOG_PRINT_L1("Range proof verified failed for output " << i);
|
addKeys(sumPseudoOuts, sumPseudoOuts, rv.pseudoOuts[i]);
|
||||||
return false;
|
}
|
||||||
|
DP(sumPseudoOuts);
|
||||||
|
|
||||||
|
//check pseudoOuts vs Outs..
|
||||||
|
if (!equalKeys(sumPseudoOuts, sumOutpks)) {
|
||||||
|
LOG_PRINT_L1("Sum check failed");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
const key message = get_pre_mlsag_hash(rv);
|
||||||
|
|
||||||
key sumOutpks = identity();
|
results.clear();
|
||||||
for (size_t i = 0; i < rv.outPk.size(); i++) {
|
results.resize(rv.mixRing.size());
|
||||||
addKeys(sumOutpks, sumOutpks, rv.outPk[i].mask);
|
tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
|
||||||
}
|
for (size_t i = 0 ; i < rv.mixRing.size() ; i++) {
|
||||||
DP(sumOutpks);
|
region.run([&, i] {
|
||||||
key txnFeeKey = scalarmultH(d2h(rv.txnFee));
|
results[i] = verRctMGSimple(message, rv.p.MGs[i], rv.mixRing[i], rv.pseudoOuts[i]);
|
||||||
addKeys(sumOutpks, txnFeeKey, sumOutpks);
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
key message = get_pre_mlsag_hash(rv);
|
for (size_t i = 0; i < results.size(); ++i) {
|
||||||
|
if (!results[i]) {
|
||||||
results.clear();
|
LOG_PRINT_L1("verRctMGSimple failed for input " << i);
|
||||||
results.resize(rv.mixRing.size());
|
return false;
|
||||||
tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
|
}
|
||||||
for (size_t i = 0 ; i < rv.mixRing.size() ; i++) {
|
|
||||||
region.run([&, i] {
|
|
||||||
results[i] = verRctMGSimple(message, rv.p.MGs[i], rv.mixRing[i], rv.pseudoOuts[i]);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
for (size_t i = 0; i < results.size(); ++i) {
|
|
||||||
if (!results[i]) {
|
|
||||||
LOG_PRINT_L1("verRctMGSimple failed for input " << i);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
key sumPseudoOuts = identity();
|
|
||||||
for (size_t i = 0 ; i < rv.mixRing.size() ; i++) {
|
|
||||||
addKeys(sumPseudoOuts, sumPseudoOuts, rv.pseudoOuts[i]);
|
|
||||||
}
|
|
||||||
DP(sumPseudoOuts);
|
|
||||||
|
|
||||||
//check pseudoOuts vs Outs..
|
|
||||||
if (!equalKeys(sumPseudoOuts, sumOutpks)) {
|
|
||||||
LOG_PRINT_L1("Sum check failed");
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -126,8 +126,10 @@ namespace rct {
|
||||||
rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & amounts, const keyV &amount_keys, const int mixin);
|
rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & amounts, const keyV &amount_keys, const int mixin);
|
||||||
rctSig genRctSimple(const key & message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & inamounts, const vector<xmr_amount> & outamounts, const keyV &amount_keys, xmr_amount txnFee, unsigned int mixin);
|
rctSig genRctSimple(const key & message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & inamounts, const vector<xmr_amount> & outamounts, const keyV &amount_keys, xmr_amount txnFee, unsigned int mixin);
|
||||||
rctSig genRctSimple(const key & message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & inamounts, const vector<xmr_amount> & outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<unsigned int> & index, ctkeyV &outSk);
|
rctSig genRctSimple(const key & message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & inamounts, const vector<xmr_amount> & outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<unsigned int> & index, ctkeyV &outSk);
|
||||||
bool verRct(const rctSig & rv);
|
bool verRct(const rctSig & rv, bool semantics);
|
||||||
bool verRctSimple(const rctSig & rv);
|
static inline bool verRct(const rctSig & rv) { return verRct(rv, true) && verRct(rv, false); }
|
||||||
|
bool verRctSimple(const rctSig & rv, bool semantics);
|
||||||
|
static inline bool verRctSimple(const rctSig & rv) { return verRctSimple(rv, true) && verRctSimple(rv, false); }
|
||||||
xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask);
|
xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask);
|
||||||
xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i);
|
xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i);
|
||||||
xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key & mask);
|
xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key & mask);
|
||||||
|
|
Loading…
Reference in a new issue