diff options
-rw-r--r-- | src/cryptonote_basic/cryptonote_boost_serialization.h | 8 | ||||
-rw-r--r-- | src/ringct/bulletproofs.cc | 103 | ||||
-rw-r--r-- | src/ringct/rctSigs.cpp | 60 | ||||
-rw-r--r-- | src/ringct/rctTypes.h | 18 |
4 files changed, 119 insertions, 70 deletions
diff --git a/src/cryptonote_basic/cryptonote_boost_serialization.h b/src/cryptonote_basic/cryptonote_boost_serialization.h index 80bd2fdc9..143133163 100644 --- a/src/cryptonote_basic/cryptonote_boost_serialization.h +++ b/src/cryptonote_basic/cryptonote_boost_serialization.h @@ -299,7 +299,7 @@ namespace boost throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type"); // a & x.message; message is not serialized, as it can be reconstructed from the tx data // a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets - if (x.type == rct::RCTTypeSimple || x.type == rct::RCTTypeSimpleBulletproof) + if (x.type == rct::RCTTypeSimple) // moved to prunable with bulletproofs a & x.pseudoOuts; a & x.ecdhInfo; serializeOutPk(a, x.outPk, ver); @@ -313,6 +313,8 @@ namespace boost if (x.rangeSigs.empty()) a & x.bulletproofs; a & x.MGs; + if (x.rangeSigs.empty()) + a & x.pseudoOuts; } template <class Archive> @@ -325,7 +327,7 @@ namespace boost throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type"); // a & x.message; message is not serialized, as it can be reconstructed from the tx data // a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets - if (x.type == rct::RCTTypeSimple || x.type == rct::RCTTypeSimpleBulletproof) + if (x.type == rct::RCTTypeSimple) a & x.pseudoOuts; a & x.ecdhInfo; serializeOutPk(a, x.outPk, ver); @@ -335,6 +337,8 @@ namespace boost if (x.p.rangeSigs.empty()) a & x.p.bulletproofs; a & x.p.MGs; + if (x.type == rct::RCTTypeSimpleBulletproof) + a & x.p.pseudoOuts; } } } diff --git a/src/ringct/bulletproofs.cc b/src/ringct/bulletproofs.cc index 67e877326..fd15ffbc4 100644 --- a/src/ringct/bulletproofs.cc +++ b/src/ringct/bulletproofs.cc @@ -297,6 +297,39 @@ static rct::keyV slice(const rct::keyV &a, size_t start, size_t stop) return res; } +static rct::key hash_cache_mash(rct::key &hash_cache, const rct::key &mash0, const rct::key &mash1) +{ + rct::keyV data; + data.reserve(3); + data.push_back(hash_cache); + data.push_back(mash0); + data.push_back(mash1); + return hash_cache = rct::hash_to_scalar(data); +} + +static rct::key hash_cache_mash(rct::key &hash_cache, const rct::key &mash0, const rct::key &mash1, const rct::key &mash2) +{ + rct::keyV data; + data.reserve(4); + data.push_back(hash_cache); + data.push_back(mash0); + data.push_back(mash1); + data.push_back(mash2); + return hash_cache = rct::hash_to_scalar(data); +} + +static rct::key hash_cache_mash(rct::key &hash_cache, const rct::key &mash0, const rct::key &mash1, const rct::key &mash2, const rct::key &mash3) +{ + rct::keyV data; + data.reserve(5); + data.push_back(hash_cache); + data.push_back(mash0); + data.push_back(mash1); + data.push_back(mash2); + data.push_back(mash3); + return hash_cache = rct::hash_to_scalar(data); +} + /* Given a value v (0..2^N-1) and a mask gamma, construct a range proof */ Bulletproof bulletproof_PROVE(const rct::key &sv, const rct::key &gamma) { @@ -329,6 +362,7 @@ Bulletproof bulletproof_PROVE(const rct::key &sv, const rct::key &gamma) } PERF_TIMER_STOP(PROVE_aLaR); + rct::key hash_cache = rct::hash_to_scalar(V); // DEBUG: Test to ensure this recovers the value #ifdef DEBUG_BP @@ -361,11 +395,8 @@ Bulletproof bulletproof_PROVE(const rct::key &sv, const rct::key &gamma) rct::addKeys(S, ve, rct::scalarmultBase(rho)); // PAPER LINES 43-45 - rct::keyV hashed; - hashed.push_back(A); - hashed.push_back(S); - rct::key y = rct::hash_to_scalar(hashed); - rct::key z = rct::hash_to_scalar(y); + rct::key y = hash_cache_mash(hash_cache, A, S); + rct::key z = hash_cache = rct::hash_to_scalar(y); // Polynomial construction before PAPER LINE 46 rct::key t0 = rct::zero(); @@ -427,11 +458,7 @@ Bulletproof bulletproof_PROVE(const rct::key &sv, const rct::key &gamma) rct::key T2 = rct::addKeys(rct::scalarmultKey(rct::H, t2), rct::scalarmultBase(tau2)); // PAPER LINES 49-51 - hashed.clear(); - hashed.push_back(z); - hashed.push_back(T1); - hashed.push_back(T2); - rct::key x = rct::hash_to_scalar(hashed); + rct::key x = hash_cache_mash(hash_cache, z, T1, T2); // PAPER LINES 52-53 rct::key taux = rct::zero(); @@ -460,12 +487,7 @@ Bulletproof bulletproof_PROVE(const rct::key &sv, const rct::key &gamma) #endif // PAPER LINES 32-33 - hashed.clear(); - hashed.push_back(x); - hashed.push_back(taux); - hashed.push_back(mu); - hashed.push_back(t); - rct::key x_ip = rct::hash_to_scalar(hashed); + rct::key x_ip = hash_cache_mash(hash_cache, x, taux, mu, t); // These are used in the inner product rounds size_t nprime = N; @@ -509,20 +531,7 @@ Bulletproof bulletproof_PROVE(const rct::key &sv, const rct::key &gamma) rct::addKeys(R[round], R[round], rct::scalarmultKey(rct::H, tmp)); // PAPER LINES 21-22 - hashed.clear(); - if (round == 0) - { - hashed.push_back(L[0]); - hashed.push_back(R[0]); - w[0] = rct::hash_to_scalar(hashed); - } - else - { - hashed.push_back(w[round - 1]); - hashed.push_back(L[round]); - hashed.push_back(R[round]); - w[round] = rct::hash_to_scalar(hashed); - } + w[round] = hash_cache_mash(hash_cache, L[round], R[round]); // PAPER LINES 24-25 const rct::key winv = invert(w[round]); @@ -563,6 +572,7 @@ bool bulletproof_VERIFY(const Bulletproof &proof) { init_exponents(); + CHECK_AND_ASSERT_MES(proof.V.size() == 1, false, "V does not have exactly one element"); CHECK_AND_ASSERT_MES(proof.L.size() == proof.R.size(), false, "Mismatched L and R sizes"); CHECK_AND_ASSERT_MES(proof.L.size() > 0, false, "Empty proof"); CHECK_AND_ASSERT_MES(proof.L.size() == 6, false, "Proof is not for 64 bits"); @@ -573,26 +583,15 @@ bool bulletproof_VERIFY(const Bulletproof &proof) // Reconstruct the challenges PERF_TIMER_START_BP(VERIFY); PERF_TIMER_START_BP(VERIFY_start); - rct::keyV hashed; - hashed.push_back(proof.A); - hashed.push_back(proof.S); - rct::key y = rct::hash_to_scalar(hashed); - rct::key z = rct::hash_to_scalar(y); - hashed.clear(); - hashed.push_back(z); - hashed.push_back(proof.T1); - hashed.push_back(proof.T2); - rct::key x = rct::hash_to_scalar(hashed); + rct::key hash_cache = rct::hash_to_scalar(proof.V[0]); + rct::key y = hash_cache_mash(hash_cache, proof.A, proof.S); + rct::key z = hash_cache = rct::hash_to_scalar(y); + rct::key x = hash_cache_mash(hash_cache, z, proof.T1, proof.T2); PERF_TIMER_STOP(VERIFY_start); PERF_TIMER_START_BP(VERIFY_line_60); // Reconstruct the challenges - hashed.clear(); - hashed.push_back(x); - hashed.push_back(proof.taux); - hashed.push_back(proof.mu); - hashed.push_back(proof.t); - rct::key x_ip = hash_to_scalar(hashed); + rct::key x_ip = hash_cache_mash(hash_cache, x, proof.taux, proof.mu, proof.t); PERF_TIMER_STOP(VERIFY_line_60); PERF_TIMER_START_BP(VERIFY_line_61); @@ -647,17 +646,9 @@ bool bulletproof_VERIFY(const Bulletproof &proof) // PAPER LINES 21-22 // The inner product challenges are computed per round rct::keyV w(rounds); - hashed.clear(); - hashed.push_back(proof.L[0]); - hashed.push_back(proof.R[0]); - w[0] = rct::hash_to_scalar(hashed); - for (size_t i = 1; i < rounds; ++i) + for (size_t i = 0; i < rounds; ++i) { - hashed.clear(); - hashed.push_back(w[i-1]); - hashed.push_back(proof.L[i]); - hashed.push_back(proof.R[i]); - w[i] = rct::hash_to_scalar(hashed); + w[i] = hash_cache_mash(hash_cache, proof.L[i], proof.R[i]); } PERF_TIMER_STOP(VERIFY_line_21_22); diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 3c34a5637..0c2be5add 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -43,6 +43,30 @@ using namespace std; #define MONERO_DEFAULT_LOG_CATEGORY "ringct" 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(); @@ -357,7 +381,8 @@ namespace rct { std::stringstream ss; binary_archive<true> ba(ss); - const size_t inputs = rv.pseudoOuts.size(); + 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 outputs = rv.ecdhInfo.size(); CHECK_AND_ASSERT_THROW_MES(const_cast<rctSig&>(rv).serialize_rctsig_base(ba, inputs, outputs), "Failed to serialize rctSigBase"); @@ -750,25 +775,26 @@ namespace rct { // TODO: unused ?? // key txnFeeKey = scalarmultH(d2h(rv.txnFee)); rv.mixRing = mixRing; - rv.pseudoOuts.resize(inamounts.size()); + keyV &pseudoOuts = bulletproof ? rv.p.pseudoOuts : rv.pseudoOuts; + pseudoOuts.resize(inamounts.size()); rv.p.MGs.resize(inamounts.size()); key sumpouts = zero(); //sum pseudoOut masks keyV a(inamounts.size()); for (i = 0 ; i < inamounts.size() - 1; i++) { skGen(a[i]); sc_add(sumpouts.bytes, a[i].bytes, sumpouts.bytes); - genC(rv.pseudoOuts[i], a[i], inamounts[i]); + genC(pseudoOuts[i], a[i], inamounts[i]); } rv.mixRing = mixRing; sc_sub(a[i].bytes, sumout.bytes, sumpouts.bytes); - genC(rv.pseudoOuts[i], a[i], inamounts[i]); - DP(rv.pseudoOuts[i]); + genC(pseudoOuts[i], a[i], inamounts[i]); + DP(pseudoOuts[i]); key full_message = get_pre_mlsag_hash(rv); if (msout) msout->c.resize(inamounts.size()); for (i = 0 ; i < inamounts.size(); i++) { - rv.p.MGs[i] = proveRctMGSimple(full_message, rv.mixRing[i], inSk[i], a[i], rv.pseudoOuts[i], kLRki ? &(*kLRki)[i]: NULL, msout ? &msout->c[i] : NULL, index[i]); + rv.p.MGs[i] = proveRctMGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], kLRki ? &(*kLRki)[i]: NULL, msout ? &msout->c[i] : NULL, index[i]); } return rv; } @@ -876,16 +902,26 @@ namespace rct { if (semantics) { if (rv.type == RCTTypeSimpleBulletproof) + { 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.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"); + } 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.pseudoOuts.size() == rv.p.MGs.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.p.MGs"); + 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"); - 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"); + 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()); @@ -894,6 +930,8 @@ namespace rct { tools::threadpool& tpool = tools::threadpool::getInstance(); tools::threadpool::waiter waiter; + const keyV &pseudoOuts = is_bulletproof(rv.type) ? rv.p.pseudoOuts : rv.pseudoOuts; + if (semantics) { key sumOutpks = identity(); for (size_t i = 0; i < rv.outPk.size(); i++) { @@ -904,8 +942,8 @@ namespace rct { addKeys(sumOutpks, txnFeeKey, sumOutpks); key sumPseudoOuts = identity(); - for (size_t i = 0 ; i < rv.pseudoOuts.size() ; i++) { - addKeys(sumPseudoOuts, sumPseudoOuts, rv.pseudoOuts[i]); + for (size_t i = 0 ; i < pseudoOuts.size() ; i++) { + addKeys(sumPseudoOuts, sumPseudoOuts, pseudoOuts[i]); } DP(sumPseudoOuts); @@ -941,7 +979,7 @@ namespace rct { 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], rv.pseudoOuts[i]); + results[i] = verRctMGSimple(message, rv.p.MGs[i], rv.mixRing[i], pseudoOuts[i]); }); } waiter.wait(); diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h index 2df797360..eba1e3d93 100644 --- a/src/ringct/rctTypes.h +++ b/src/ringct/rctTypes.h @@ -246,7 +246,7 @@ namespace rct { // inputs/outputs not saved, only here for serialization help // FIELD(message) - not serialized, it can be reconstructed // FIELD(mixRing) - not serialized, it can be reconstructed - if (type == RCTTypeSimple || type == RCTTypeSimpleBulletproof) + if (type == RCTTypeSimple) // moved to prunable with bulletproofs { ar.tag("pseudoOuts"); ar.begin_array(); @@ -294,6 +294,7 @@ namespace rct { std::vector<rangeSig> rangeSigs; std::vector<Bulletproof> bulletproofs; std::vector<mgSig> MGs; // simple rct has N, full has 1 + keyV pseudoOuts; //C - for simple rct template<bool W, template <bool> class Archive> bool serialize_rctsig_prunable(Archive<W> &ar, uint8_t type, size_t inputs, size_t outputs, size_t mixin) @@ -381,6 +382,21 @@ namespace rct { ar.delimit_array(); } ar.end_array(); + if (type == RCTTypeSimpleBulletproof) + { + ar.tag("pseudoOuts"); + ar.begin_array(); + PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, pseudoOuts); + if (pseudoOuts.size() != inputs) + return false; + for (size_t i = 0; i < inputs; ++i) + { + FIELDS(pseudoOuts[i]) + if (inputs - i > 1) + ar.delimit_array(); + } + ar.end_array(); + } return true; } |