aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cryptonote_basic/cryptonote_boost_serialization.h8
-rw-r--r--src/ringct/bulletproofs.cc103
-rw-r--r--src/ringct/rctSigs.cpp60
-rw-r--r--src/ringct/rctTypes.h18
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;
}