rct: split rct checks between semantics and other
Semantics can be checked early
This commit is contained in:
parent
2806842200
commit
ba3968f6ce
|
@ -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));
|
||||
}
|
||||
|
||||
// outPk
|
||||
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);
|
||||
// outPk was already done by handle_incoming_tx
|
||||
|
||||
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!");
|
||||
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!");
|
||||
return false;
|
||||
|
|
|
@ -49,6 +49,7 @@ using namespace epee;
|
|||
#if defined(BERKELEY_DB)
|
||||
#include "blockchain_db/berkeleydb/db_bdb.h"
|
||||
#endif
|
||||
#include "ringct/rctSigs.h"
|
||||
|
||||
DISABLE_VS_WARNINGS(4355)
|
||||
|
||||
|
@ -494,6 +495,22 @@ namespace cryptonote
|
|||
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))
|
||||
{
|
||||
LOG_PRINT_L1("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " semantic, rejected");
|
||||
|
@ -584,6 +601,33 @@ namespace cryptonote
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -710,43 +710,54 @@ namespace rct {
|
|||
//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
|
||||
// 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);
|
||||
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");
|
||||
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");
|
||||
if (semantics)
|
||||
{
|
||||
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
|
||||
try
|
||||
{
|
||||
std::deque<bool> results(rv.outPk.size(), false);
|
||||
tools::thread_group threadpool(tools::thread_group::optimal_with_max(rv.outPk.size()));
|
||||
if (semantics) {
|
||||
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) {
|
||||
DP("range proofs verified?");
|
||||
for (size_t i = 0; i < rv.outPk.size(); i++) {
|
||||
region.run([&, i] {
|
||||
results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
|
||||
});
|
||||
}
|
||||
});
|
||||
tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
|
||||
DP("range proofs verified?");
|
||||
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 < rv.outPk.size(); ++i) {
|
||||
if (!results[i]) {
|
||||
LOG_PRINT_L1("Range proof verified failed for output " << i);
|
||||
return false;
|
||||
for (size_t i = 0; i < rv.outPk.size(); ++i) {
|
||||
if (!results[i]) {
|
||||
LOG_PRINT_L1("Range proof verified failed for output " << i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//compute txn fee
|
||||
key txnFeeKey = scalarmultH(d2h(rv.txnFee));
|
||||
bool mgVerd = verRctMG(rv.p.MGs[0], rv.mixRing, rv.outPk, txnFeeKey, get_pre_mlsag_hash(rv));
|
||||
DP("mg sig verified?");
|
||||
DP(mgVerd);
|
||||
if (!mgVerd) {
|
||||
LOG_PRINT_L1("MG signature verification failed");
|
||||
return false;
|
||||
if (!semantics) {
|
||||
//compute txn fee
|
||||
key txnFeeKey = scalarmultH(d2h(rv.txnFee));
|
||||
bool mgVerd = verRctMG(rv.p.MGs[0], rv.mixRing, rv.outPk, txnFeeKey, get_pre_mlsag_hash(rv));
|
||||
DP("mg sig verified?");
|
||||
DP(mgVerd);
|
||||
if (!mgVerd) {
|
||||
LOG_PRINT_L1("MG signature verification failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -759,76 +770,86 @@ namespace rct {
|
|||
|
||||
//ver RingCT simple
|
||||
//assumes only post-rct style inputs (at least for max anonymity)
|
||||
bool verRctSimple(const rctSig & rv) {
|
||||
bool verRctSimple(const rctSig & rv, bool semantics) {
|
||||
try
|
||||
{
|
||||
PERF_TIMER(verRctSimple);
|
||||
|
||||
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");
|
||||
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.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.pseudoOuts and mixRing");
|
||||
if (semantics)
|
||||
{
|
||||
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.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());
|
||||
|
||||
std::deque<bool> results(threads);
|
||||
tools::thread_group threadpool(tools::thread_group::optimal_with_max(threads));
|
||||
|
||||
results.clear();
|
||||
results.resize(rv.outPk.size());
|
||||
tools::task_region(threadpool, [&] (tools::task_region_handle& region) {
|
||||
if (semantics) {
|
||||
results.clear();
|
||||
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++) {
|
||||
region.run([&, i] {
|
||||
results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
|
||||
});
|
||||
addKeys(sumOutpks, sumOutpks, rv.outPk[i].mask);
|
||||
}
|
||||
});
|
||||
DP(sumOutpks);
|
||||
key txnFeeKey = scalarmultH(d2h(rv.txnFee));
|
||||
addKeys(sumOutpks, txnFeeKey, sumOutpks);
|
||||
|
||||
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 sumPseudoOuts = identity();
|
||||
for (size_t i = 0 ; i < rv.pseudoOuts.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;
|
||||
}
|
||||
}
|
||||
else {
|
||||
const key message = get_pre_mlsag_hash(rv);
|
||||
|
||||
key sumOutpks = identity();
|
||||
for (size_t i = 0; i < rv.outPk.size(); i++) {
|
||||
addKeys(sumOutpks, sumOutpks, rv.outPk[i].mask);
|
||||
}
|
||||
DP(sumOutpks);
|
||||
key txnFeeKey = scalarmultH(d2h(rv.txnFee));
|
||||
addKeys(sumOutpks, txnFeeKey, sumOutpks);
|
||||
results.clear();
|
||||
results.resize(rv.mixRing.size());
|
||||
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]);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
key message = get_pre_mlsag_hash(rv);
|
||||
|
||||
results.clear();
|
||||
results.resize(rv.mixRing.size());
|
||||
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;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
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;
|
||||
|
|
|
@ -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 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);
|
||||
bool verRct(const rctSig & rv);
|
||||
bool verRctSimple(const rctSig & rv);
|
||||
bool verRct(const rctSig & rv, bool semantics);
|
||||
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);
|
||||
xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key & mask);
|
||||
|
|
Loading…
Reference in New Issue