aboutsummaryrefslogtreecommitdiff
path: root/src/ringct/rctSigs.cpp
diff options
context:
space:
mode:
authormoneromooo-monero <moneromooo-monero@users.noreply.github.com>2018-02-03 14:36:29 +0000
committermoneromooo-monero <moneromooo-monero@users.noreply.github.com>2018-09-11 13:37:32 +0000
commitbacf0a1e2ff54ef1fc77e3f6ec92e87946084c1a (patch)
tree6d1ec247c11b7f9759dc0f169f98b5804daad1df /src/ringct/rctSigs.cpp
parentmake straus cached mode thread safe, and add tests for it (diff)
downloadmonero-bacf0a1e2ff54ef1fc77e3f6ec92e87946084c1a.tar.xz
bulletproofs: add aggregated verification
Ported from sarang's java code
Diffstat (limited to 'src/ringct/rctSigs.cpp')
-rw-r--r--src/ringct/rctSigs.cpp163
1 files changed, 111 insertions, 52 deletions
diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp
index 6dcb203bf..2e2b07fcc 100644
--- a/src/ringct/rctSigs.cpp
+++ b/src/ringct/rctSigs.cpp
@@ -70,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;
@@ -918,15 +925,23 @@ 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");
- const bool bulletproof = is_rct_bulletproof(rv.type);
- 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)
{
+ CHECK_AND_ASSERT_MES(rvp, false, "rctSig pointer is NULL");
+ const rctSig &rv = *rvp;
+ CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeSimpleBulletproof, false, "verRctSemanticsSimple called on non simple rctSig");
+ const bool bulletproof = is_rct_bulletproof(rv.type);
if (bulletproof)
{
CHECK_AND_ASSERT_MES(rv.outPk.size() == n_bulletproof_amounts(rv.p.bulletproofs), false, "Mismatched sizes of outPk and bulletproofs");
@@ -940,28 +955,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 (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());
+ 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 = bulletproof ? 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));
@@ -969,50 +978,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(bulletproof ? rv.p.bulletproofs.size() : rv.outPk.size());
if (bulletproof)
+ {
for (size_t i = 0; i < rv.p.bulletproofs.size(); i++)
- tpool.submit(&waiter, [&, i] { results[i] = verBulletproof(rv.p.bulletproofs[i]); });
+ proofs.push_back(&rv.p.bulletproofs[i]);
+ }
else
+ {
for (size_t i = 0; i < rv.p.rangeSigs.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 < results.size(); ++i) {
- if (!results[i]) {
- LOG_PRINT_L1("Range proof verified failed for proof " << i);
- return false;
- }
+ 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 == RCTTypeSimpleBulletproof, 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;
}
}
@@ -1021,12 +1080,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;
}
}