aboutsummaryrefslogtreecommitdiff
path: root/src/ringct/rctSigs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ringct/rctSigs.cpp')
-rw-r--r--src/ringct/rctSigs.cpp343
1 files changed, 208 insertions, 135 deletions
diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp
index f74216ed4..fe0cd9c57 100644
--- a/src/ringct/rctSigs.cpp
+++ b/src/ringct/rctSigs.cpp
@@ -45,30 +45,6 @@ using namespace std;
#define CHECK_AND_ASSERT_MES_L1(expr, ret, message) {if(!(expr)) {MCERROR("verify", message); return ret;}}
namespace rct {
- bool is_simple(int type)
- {
- switch (type)
- {
- case RCTTypeSimple:
- case RCTTypeSimpleBulletproof:
- return true;
- default:
- return false;
- }
- }
-
- bool is_bulletproof(int type)
- {
- switch (type)
- {
- case RCTTypeSimpleBulletproof:
- case RCTTypeFullBulletproof:
- return true;
- default:
- return false;
- }
- }
-
Bulletproof proveRangeBulletproof(key &C, key &mask, uint64_t amount)
{
mask = rct::skGen();
@@ -78,6 +54,15 @@ namespace rct {
return proof;
}
+ Bulletproof proveRangeBulletproof(keyV &C, keyV &masks, const std::vector<uint64_t> &amounts)
+ {
+ masks = rct::skvGen(amounts.size());
+ Bulletproof proof = bulletproof_PROVE(amounts, masks);
+ CHECK_AND_ASSERT_THROW_MES(proof.V.size() == amounts.size(), "V does not have the expected size");
+ C = proof.V;
+ return proof;
+ }
+
bool verBulletproof(const Bulletproof &proof)
{
try { return bulletproof_VERIFY(proof); }
@@ -85,6 +70,13 @@ namespace rct {
catch (...) { return false; }
}
+ bool verBulletproof(const std::vector<const Bulletproof*> &proofs)
+ {
+ try { return bulletproof_VERIFY(proofs); }
+ // we can get deep throws from ge_frombytes_vartime if input isn't valid
+ catch (...) { return false; }
+ }
+
//Borromean (c.f. gmax/andytoshi's paper)
boroSig genBorromean(const key64 x, const key64 P1, const key64 P2, const bits indices) {
key64 L[2], alpha;
@@ -285,6 +277,7 @@ namespace rct {
for (j = 0; j < dsRows; j++) {
addKeys2(L, rv.ss[i][j], c_old, pk[i][j]);
hashToPoint(Hi, pk[i][j]);
+ CHECK_AND_ASSERT_MES(!(Hi == rct::identity()), false, "Data hashed to point at infinity");
addKeys3(R, rv.ss[i][j], Hi, c_old, Ip[j].k);
toHash[3 * j + 1] = pk[i][j];
toHash[3 * j + 2] = L;
@@ -389,7 +382,7 @@ namespace rct {
std::stringstream ss;
binary_archive<true> ba(ss);
CHECK_AND_ASSERT_THROW_MES(!rv.mixRing.empty(), "Empty mixRing");
- const size_t inputs = is_simple(rv.type) ? rv.mixRing.size() : rv.mixRing[0].size();
+ const size_t inputs = is_rct_simple(rv.type) ? rv.mixRing.size() : rv.mixRing[0].size();
const size_t outputs = rv.ecdhInfo.size();
key prehash;
CHECK_AND_ASSERT_THROW_MES(const_cast<rctSig&>(rv).serialize_rctsig_base(ba, inputs, outputs),
@@ -398,7 +391,7 @@ namespace rct {
hashes.push_back(hash2rct(h));
keyV kv;
- if (rv.type == RCTTypeSimpleBulletproof || rv.type == RCTTypeFullBulletproof)
+ if (rv.type == RCTTypeBulletproof)
{
kv.reserve((6*2+9) * rv.p.bulletproofs.size());
for (const auto &p: rv.p.bulletproofs)
@@ -492,7 +485,9 @@ namespace rct {
for (size_t j = 0; j < outPk.size(); j++) {
sc_sub(sk[rows].bytes, sk[rows].bytes, outSk[j].mask.bytes); //subtract output masks in last row..
}
- return MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows, hwdev);
+ mgSig result = MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows, hwdev);
+ memwipe(sk.data(), sk.size() * sizeof(key));
+ return result;
}
@@ -521,7 +516,9 @@ namespace rct {
M[i][0] = pubs[i].dest;
subKeys(M[i][1], pubs[i].mask, Cout);
}
- return MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows, hwdev);
+ mgSig result = MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows, hwdev);
+ memwipe(&sk[0], sizeof(key));
+ return result;
}
@@ -655,7 +652,7 @@ namespace rct {
// must know the destination private key to find the correct amount, else will return a random number
// Note: For txn fees, the last index in the amounts vector should contain that
// Thus the amounts vector will be "one" longer than the destinations vectort
- rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, bool bulletproof, hw::device &hwdev) {
+ rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, hw::device &hwdev) {
CHECK_AND_ASSERT_THROW_MES(amounts.size() == destinations.size() || amounts.size() == destinations.size() + 1, "Different number of amounts/destinations");
CHECK_AND_ASSERT_THROW_MES(amount_keys.size() == destinations.size(), "Different number of amount_keys/destinations");
CHECK_AND_ASSERT_THROW_MES(index < mixRing.size(), "Bad index into mixRing");
@@ -665,13 +662,10 @@ namespace rct {
CHECK_AND_ASSERT_THROW_MES((kLRki && msout) || (!kLRki && !msout), "Only one of kLRki/msout is present");
rctSig rv;
- rv.type = bulletproof ? RCTTypeFullBulletproof : RCTTypeFull;
+ rv.type = RCTTypeFull;
rv.message = message;
rv.outPk.resize(destinations.size());
- if (bulletproof)
- rv.p.bulletproofs.resize(destinations.size());
- else
- rv.p.rangeSigs.resize(destinations.size());
+ rv.p.rangeSigs.resize(destinations.size());
rv.ecdhInfo.resize(destinations.size());
size_t i = 0;
@@ -681,17 +675,10 @@ namespace rct {
//add destination to sig
rv.outPk[i].dest = copy(destinations[i]);
//compute range proof
- if (bulletproof)
- rv.p.bulletproofs[i] = proveRangeBulletproof(rv.outPk[i].mask, outSk[i].mask, amounts[i]);
- else
- rv.p.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, amounts[i]);
+ rv.p.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, amounts[i]);
#ifdef DBG
- if (bulletproof)
- CHECK_AND_ASSERT_THROW_MES(verBulletproof(rv.p.bulletproofs[i]), "verBulletproof failed on newly created proof");
- else
- CHECK_AND_ASSERT_THROW_MES(verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]), "verRange failed on newly created proof");
+ CHECK_AND_ASSERT_THROW_MES(verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]), "verRange failed on newly created proof");
#endif
-
//mask amount and mask
rv.ecdhInfo[i].mask = copy(outSk[i].mask);
rv.ecdhInfo[i].amount = d2h(amounts[i]);
@@ -721,12 +708,13 @@ namespace rct {
ctkeyM mixRing;
ctkeyV outSk;
tie(mixRing, index) = populateFromBlockchain(inPk, mixin);
- return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, kLRki, msout, index, outSk, false, hwdev);
+ return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, kLRki, msout, index, outSk, hwdev);
}
//RCT simple
//for post-rct only
- 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<multisig_kLRki> *kLRki, multisig_out *msout, const std::vector<unsigned int> & index, ctkeyV &outSk, bool bulletproof, hw::device &hwdev) {
+ 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<multisig_kLRki> *kLRki, multisig_out *msout, const std::vector<unsigned int> & index, ctkeyV &outSk, RangeProofType range_proof_type, hw::device &hwdev) {
+ const bool bulletproof = range_proof_type != RangeProofBorromean;
CHECK_AND_ASSERT_THROW_MES(inamounts.size() > 0, "Empty inamounts");
CHECK_AND_ASSERT_THROW_MES(inamounts.size() == inSk.size(), "Different number of inamounts/inSk");
CHECK_AND_ASSERT_THROW_MES(outamounts.size() == destinations.size(), "Different number of amounts/destinations");
@@ -742,35 +730,74 @@ namespace rct {
}
rctSig rv;
- rv.type = bulletproof ? RCTTypeSimpleBulletproof : RCTTypeSimple;
+ rv.type = bulletproof ? RCTTypeBulletproof : RCTTypeSimple;
rv.message = message;
rv.outPk.resize(destinations.size());
- if (bulletproof)
- rv.p.bulletproofs.resize(destinations.size());
- else
+ if (!bulletproof)
rv.p.rangeSigs.resize(destinations.size());
rv.ecdhInfo.resize(destinations.size());
size_t i;
keyV masks(destinations.size()); //sk mask..
outSk.resize(destinations.size());
- key sumout = zero();
for (i = 0; i < destinations.size(); i++) {
//add destination to sig
rv.outPk[i].dest = copy(destinations[i]);
//compute range proof
- if (bulletproof)
- rv.p.bulletproofs[i] = proveRangeBulletproof(rv.outPk[i].mask, outSk[i].mask, outamounts[i]);
- else
+ if (!bulletproof)
rv.p.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, outamounts[i]);
#ifdef DBG
- if (bulletproof)
- CHECK_AND_ASSERT_THROW_MES(verBulletproof(rv.p.bulletproofs[i]), "verBulletproof failed on newly created proof");
- else
+ if (!bulletproof)
CHECK_AND_ASSERT_THROW_MES(verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]), "verRange failed on newly created proof");
#endif
-
+ }
+
+ rv.p.bulletproofs.clear();
+ if (bulletproof)
+ {
+ std::vector<uint64_t> proof_amounts;
+ size_t n_amounts = outamounts.size();
+ size_t amounts_proved = 0;
+ if (range_proof_type == RangeProofPaddedBulletproof)
+ {
+ rct::keyV C, masks;
+ rv.p.bulletproofs.push_back(proveRangeBulletproof(C, masks, outamounts));
+ #ifdef DBG
+ CHECK_AND_ASSERT_THROW_MES(verBulletproof(rv.p.bulletproofs.back()), "verBulletproof failed on newly created proof");
+ #endif
+ for (i = 0; i < outamounts.size(); ++i)
+ {
+ rv.outPk[i].mask = rct::scalarmult8(C[i]);
+ outSk[i].mask = masks[i];
+ }
+ }
+ else while (amounts_proved < n_amounts)
+ {
+ size_t batch_size = 1;
+ if (range_proof_type == RangeProofMultiOutputBulletproof)
+ while (batch_size * 2 + amounts_proved <= n_amounts && batch_size * 2 <= BULLETPROOF_MAX_OUTPUTS)
+ batch_size *= 2;
+ rct::keyV C, masks;
+ std::vector<uint64_t> batch_amounts(batch_size);
+ for (i = 0; i < batch_size; ++i)
+ batch_amounts[i] = outamounts[i + amounts_proved];
+ rv.p.bulletproofs.push_back(proveRangeBulletproof(C, masks, batch_amounts));
+ #ifdef DBG
+ CHECK_AND_ASSERT_THROW_MES(verBulletproof(rv.p.bulletproofs.back()), "verBulletproof failed on newly created proof");
+ #endif
+ for (i = 0; i < batch_size; ++i)
+ {
+ rv.outPk[i + amounts_proved].mask = rct::scalarmult8(C[i]);
+ outSk[i + amounts_proved].mask = masks[i];
+ }
+ amounts_proved += batch_size;
+ }
+ }
+
+ key sumout = zero();
+ for (i = 0; i < outSk.size(); ++i)
+ {
sc_add(sumout.bytes, outSk[i].mask.bytes, sumout.bytes);
//mask amount and mask
@@ -818,7 +845,7 @@ namespace rct {
mixRing[i].resize(mixin+1);
index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin);
}
- return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, amount_keys, kLRki, msout, index, outSk, false, hwdev);
+ return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, amount_keys, kLRki, msout, index, outSk, RangeProofBorromean, hwdev);
}
//RingCT protocol
@@ -833,13 +860,10 @@ namespace rct {
// must know the destination private key to find the correct amount, else will return a random number
bool verRct(const rctSig & rv, bool semantics) {
PERF_TIMER(verRct);
- CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull || rv.type == RCTTypeFullBulletproof, false, "verRct called on non-full rctSig");
+ CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "verRct called on non-full rctSig");
if (semantics)
{
- if (rv.type == RCTTypeFullBulletproof)
- CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.bulletproofs.size(), false, "Mismatched sizes of outPk and rv.p.bulletproofs");
- else
- 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.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");
}
@@ -856,19 +880,13 @@ namespace rct {
tools::threadpool::waiter waiter;
std::deque<bool> results(rv.outPk.size(), false);
DP("range proofs verified?");
- for (size_t i = 0; i < rv.outPk.size(); i++) {
- tpool.submit(&waiter, [&, i] {
- if (rv.p.rangeSigs.empty())
- results[i] = verBulletproof(rv.p.bulletproofs[i]);
- else
- results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
- }, true);
- }
+ for (size_t i = 0; i < rv.outPk.size(); i++)
+ tpool.submit(&waiter, [&, i] { results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]); });
waiter.wait(&tpool);
- for (size_t i = 0; i < rv.outPk.size(); ++i) {
+ for (size_t i = 0; i < results.size(); ++i) {
if (!results[i]) {
- LOG_PRINT_L1("Range proof verified failed for output " << i);
+ LOG_PRINT_L1("Range proof verified failed for proof " << i);
return false;
}
}
@@ -902,17 +920,26 @@ namespace rct {
//ver RingCT simple
//assumes only post-rct style inputs (at least for max anonymity)
- bool verRctSimple(const rctSig & rv, bool semantics) {
+ bool verRctSemanticsSimple(const std::vector<const rctSig*> & rvv) {
try
{
- PERF_TIMER(verRctSimple);
+ PERF_TIMER(verRctSemanticsSimple);
- CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeSimpleBulletproof, false, "verRctSimple called on non simple rctSig");
- if (semantics)
+ tools::threadpool& tpool = tools::threadpool::getInstance();
+ tools::threadpool::waiter waiter;
+ std::deque<bool> results;
+ std::vector<const Bulletproof*> proofs;
+ size_t max_non_bp_proofs = 0, offset = 0;
+
+ for (const rctSig *rvp: rvv)
{
- if (rv.type == RCTTypeSimpleBulletproof)
+ CHECK_AND_ASSERT_MES(rvp, false, "rctSig pointer is NULL");
+ const rctSig &rv = *rvp;
+ CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof, false, "verRctSemanticsSimple called on non simple rctSig");
+ const bool bulletproof = is_rct_bulletproof(rv.type);
+ if (bulletproof)
{
- CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.bulletproofs.size(), false, "Mismatched sizes of outPk and rv.p.bulletproofs");
+ CHECK_AND_ASSERT_MES(rv.outPk.size() == n_bulletproof_amounts(rv.p.bulletproofs), false, "Mismatched sizes of outPk and bulletproofs");
CHECK_AND_ASSERT_MES(rv.p.pseudoOuts.size() == rv.p.MGs.size(), false, "Mismatched sizes of rv.p.pseudoOuts and rv.p.MGs");
CHECK_AND_ASSERT_MES(rv.pseudoOuts.empty(), false, "rv.pseudoOuts is not empty");
}
@@ -923,28 +950,22 @@ namespace rct {
CHECK_AND_ASSERT_MES(rv.p.pseudoOuts.empty(), false, "rv.p.pseudoOuts is not empty");
}
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo");
- }
- else
- {
- // semantics check is early, and mixRing/MGs aren't resolved yet
- if (rv.type == RCTTypeSimpleBulletproof)
- CHECK_AND_ASSERT_MES(rv.p.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.p.pseudoOuts and mixRing");
- else
- 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());
+ if (!bulletproof)
+ max_non_bp_proofs += rv.p.rangeSigs.size();
+ }
- std::deque<bool> results(threads);
- tools::threadpool& tpool = tools::threadpool::getInstance();
- tools::threadpool::waiter waiter;
+ results.resize(max_non_bp_proofs);
+ for (const rctSig *rvp: rvv)
+ {
+ const rctSig &rv = *rvp;
- const keyV &pseudoOuts = is_bulletproof(rv.type) ? rv.p.pseudoOuts : rv.pseudoOuts;
+ const bool bulletproof = is_rct_bulletproof(rv.type);
+ const keyV &pseudoOuts = bulletproof ? rv.p.pseudoOuts : rv.pseudoOuts;
- if (semantics) {
key sumOutpks = identity();
for (size_t i = 0; i < rv.outPk.size(); i++) {
- addKeys(sumOutpks, sumOutpks, rv.outPk[i].mask);
+ addKeys(sumOutpks, sumOutpks, rv.outPk[i].mask);
}
DP(sumOutpks);
key txnFeeKey = scalarmultH(d2h(rv.txnFee));
@@ -952,52 +973,100 @@ namespace rct {
key sumPseudoOuts = identity();
for (size_t i = 0 ; i < pseudoOuts.size() ; i++) {
- addKeys(sumPseudoOuts, sumPseudoOuts, pseudoOuts[i]);
+ addKeys(sumPseudoOuts, sumPseudoOuts, pseudoOuts[i]);
}
DP(sumPseudoOuts);
//check pseudoOuts vs Outs..
if (!equalKeys(sumPseudoOuts, sumOutpks)) {
- LOG_PRINT_L1("Sum check failed");
- return false;
+ LOG_PRINT_L1("Sum check failed");
+ return false;
}
- results.clear();
- results.resize(rv.outPk.size());
- for (size_t i = 0; i < rv.outPk.size(); i++) {
- tpool.submit(&waiter, [&, i] {
- if (rv.p.rangeSigs.empty())
- results[i] = verBulletproof(rv.p.bulletproofs[i]);
- else
- results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
- }, true);
+ if (bulletproof)
+ {
+ for (size_t i = 0; i < rv.p.bulletproofs.size(); i++)
+ proofs.push_back(&rv.p.bulletproofs[i]);
}
- waiter.wait(&tpool);
-
- for (size_t i = 0; i < results.size(); ++i) {
- if (!results[i]) {
- LOG_PRINT_L1("Range proof verified failed for output " << i);
- return false;
- }
+ else
+ {
+ for (size_t i = 0; i < rv.p.rangeSigs.size(); i++)
+ tpool.submit(&waiter, [&, i, offset] { results[i+offset] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]); });
+ offset += rv.p.rangeSigs.size();
}
}
- else {
- const key message = get_pre_mlsag_hash(rv, hw::get_device("default"));
-
- results.clear();
- results.resize(rv.mixRing.size());
- for (size_t i = 0 ; i < rv.mixRing.size() ; i++) {
- tpool.submit(&waiter, [&, i] {
- results[i] = verRctMGSimple(message, rv.p.MGs[i], rv.mixRing[i], pseudoOuts[i]);
- }, true);
+ if (!proofs.empty() && !verBulletproof(proofs))
+ {
+ LOG_PRINT_L1("Aggregate range proof verified failed");
+ return false;
+ }
+
+ waiter.wait(&tpool);
+ for (size_t i = 0; i < results.size(); ++i) {
+ if (!results[i]) {
+ LOG_PRINT_L1("Range proof verified failed for proof " << i);
+ return false;
}
- waiter.wait(&tpool);
+ }
- for (size_t i = 0; i < results.size(); ++i) {
- if (!results[i]) {
- LOG_PRINT_L1("verRctMGSimple failed for input " << i);
- return false;
- }
+ return true;
+ }
+ // we can get deep throws from ge_frombytes_vartime if input isn't valid
+ catch (const std::exception &e)
+ {
+ LOG_PRINT_L1("Error in verRctSemanticsSimple: " << e.what());
+ return false;
+ }
+ catch (...)
+ {
+ LOG_PRINT_L1("Error in verRctSemanticsSimple, but not an actual exception");
+ return false;
+ }
+ }
+
+ bool verRctSemanticsSimple(const rctSig & rv)
+ {
+ return verRctSemanticsSimple(std::vector<const rctSig*>(1, &rv));
+ }
+
+ //ver RingCT simple
+ //assumes only post-rct style inputs (at least for max anonymity)
+ bool verRctNonSemanticsSimple(const rctSig & rv) {
+ try
+ {
+ PERF_TIMER(verRctNonSemanticsSimple);
+
+ CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof, false, "verRctNonSemanticsSimple called on non simple rctSig");
+ const bool bulletproof = is_rct_bulletproof(rv.type);
+ // semantics check is early, and mixRing/MGs aren't resolved yet
+ if (bulletproof)
+ CHECK_AND_ASSERT_MES(rv.p.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.p.pseudoOuts and mixRing");
+ else
+ 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::threadpool& tpool = tools::threadpool::getInstance();
+ tools::threadpool::waiter waiter;
+
+ const keyV &pseudoOuts = bulletproof ? rv.p.pseudoOuts : rv.pseudoOuts;
+
+ const key message = get_pre_mlsag_hash(rv, hw::get_device("default"));
+
+ results.clear();
+ results.resize(rv.mixRing.size());
+ for (size_t i = 0 ; i < rv.mixRing.size() ; i++) {
+ tpool.submit(&waiter, [&, i] {
+ results[i] = verRctMGSimple(message, rv.p.MGs[i], rv.mixRing[i], pseudoOuts[i]);
+ });
+ }
+ waiter.wait(&tpool);
+
+ for (size_t i = 0; i < results.size(); ++i) {
+ if (!results[i]) {
+ LOG_PRINT_L1("verRctMGSimple failed for input " << i);
+ return false;
}
}
@@ -1006,12 +1075,12 @@ namespace rct {
// we can get deep throws from ge_frombytes_vartime if input isn't valid
catch (const std::exception &e)
{
- LOG_PRINT_L1("Error in verRct: " << e.what());
+ LOG_PRINT_L1("Error in verRctNonSemanticsSimple: " << e.what());
return false;
}
catch (...)
{
- LOG_PRINT_L1("Error in verRct, but not an actual exception");
+ LOG_PRINT_L1("Error in verRctNonSemanticsSimple, but not an actual exception");
return false;
}
}
@@ -1027,7 +1096,7 @@ namespace rct {
// 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
xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask, hw::device &hwdev) {
- CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull || rv.type == RCTTypeFullBulletproof, false, "decodeRct called on non-full rctSig");
+ CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "decodeRct called on non-full rctSig");
CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index");
CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo");
@@ -1040,6 +1109,8 @@ namespace rct {
DP("C");
DP(C);
key Ctmp;
+ CHECK_AND_ASSERT_THROW_MES(sc_check(mask.bytes) == 0, "warning, bad ECDH mask");
+ CHECK_AND_ASSERT_THROW_MES(sc_check(amount.bytes) == 0, "warning, bad ECDH amount");
addKeys2(Ctmp, mask, amount, H);
DP("Ctmp");
DP(Ctmp);
@@ -1055,7 +1126,7 @@ namespace rct {
}
xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask, hw::device &hwdev) {
- CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeSimpleBulletproof, false, "decodeRct called on non simple rctSig");
+ CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof, false, "decodeRct called on non simple rctSig");
CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index");
CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo");
@@ -1068,6 +1139,8 @@ namespace rct {
DP("C");
DP(C);
key Ctmp;
+ CHECK_AND_ASSERT_THROW_MES(sc_check(mask.bytes) == 0, "warning, bad ECDH mask");
+ CHECK_AND_ASSERT_THROW_MES(sc_check(amount.bytes) == 0, "warning, bad ECDH amount");
addKeys2(Ctmp, mask, amount, H);
DP("Ctmp");
DP(Ctmp);
@@ -1083,12 +1156,12 @@ namespace rct {
}
bool signMultisig(rctSig &rv, const std::vector<unsigned int> &indices, const keyV &k, const multisig_out &msout, const key &secret_key) {
- CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull || rv.type == RCTTypeSimple || rv.type == RCTTypeFullBulletproof || rv.type == RCTTypeSimpleBulletproof,
+ CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull || rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof,
false, "unsupported rct type");
CHECK_AND_ASSERT_MES(indices.size() == k.size(), false, "Mismatched k/indices sizes");
CHECK_AND_ASSERT_MES(k.size() == rv.p.MGs.size(), false, "Mismatched k/MGs size");
CHECK_AND_ASSERT_MES(k.size() == msout.c.size(), false, "Mismatched k/msout.c size");
- if (rv.type == RCTTypeFull || rv.type == RCTTypeFullBulletproof)
+ if (rv.type == RCTTypeFull)
{
CHECK_AND_ASSERT_MES(rv.p.MGs.size() == 1, false, "MGs not a single element");
}