diff options
author | Riccardo Spagni <ric@spagni.net> | 2017-12-08 23:30:51 +0200 |
---|---|---|
committer | Riccardo Spagni <ric@spagni.net> | 2017-12-08 23:30:51 +0200 |
commit | 782a84f7b490baa10afef94dd6954d6ab50d020b (patch) | |
tree | 099cf5e07386236924d312606a2e4569658a1fb8 /src/ringct/rctSigs.cpp | |
parent | Merge pull request #2845 (diff) | |
parent | add bulletproofs from v7 on testnet (diff) | |
download | monero-782a84f7b490baa10afef94dd6954d6ab50d020b.tar.xz |
Merge pull request #2883
c83d0b3e add bulletproofs from v7 on testnet (moneromooo-monero)
8620ef0a bulletproofs: switch H/G in Pedersen commitments to match rct (moneromooo-monero)
d58835b2 integrate bulletproofs into monero (moneromooo-monero)
90b8d9f2 add bulletproofs to the build, with basic unit tests (moneromooo-monero)
fe120264 perf_timer: add non scoped start/stop timer defines (moneromooo-monero)
ada42914 add a version of ge_double_scalarmult_precomp_vartime with A precomp (moneromooo-monero)
d43eef6d ringct: add a version of addKeys which returns the result (moneromooo-monero)
7ff07928 sc_mul and sc_muladd (luigi1111)
3d0b54bd epee: add do while(0) around brace statement in a macro (moneromooo-monero)
Diffstat (limited to '')
-rw-r--r-- | src/ringct/rctSigs.cpp | 147 |
1 files changed, 114 insertions, 33 deletions
diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 946325367..cfb4aaf97 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -33,6 +33,7 @@ #include "common/threadpool.h" #include "common/util.h" #include "rctSigs.h" +#include "bulletproofs.h" #include "cryptonote_basic/cryptonote_format_utils.h" using namespace crypto; @@ -42,6 +43,15 @@ using namespace std; #define MONERO_DEFAULT_LOG_CATEGORY "ringct" namespace rct { + Bulletproof proveRangeBulletproof(key &C, key &mask, uint64_t amount) + { + mask = rct::skGen(); + Bulletproof proof = bulletproof_PROVE(amount, mask); + CHECK_AND_ASSERT_THROW_MES(proof.V.size() == 1, "V has not exactly one element"); + C = proof.V[0]; + return proof; + } + //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; @@ -335,16 +345,41 @@ namespace rct { hashes.push_back(hash2rct(h)); keyV kv; - kv.reserve((64*3+1) * rv.p.rangeSigs.size()); - for (auto r: rv.p.rangeSigs) + if (rv.type == RCTTypeSimpleBulletproof || rv.type == RCTTypeFullBulletproof) + { + kv.reserve((6*2+10) * rv.p.bulletproofs.size()); + for (const auto &p: rv.p.bulletproofs) + { + for (size_t n = 0; n < p.V.size(); ++n) + kv.push_back(p.V[n]); + kv.push_back(p.A); + kv.push_back(p.S); + kv.push_back(p.T1); + kv.push_back(p.T2); + kv.push_back(p.taux); + kv.push_back(p.mu); + for (size_t n = 0; n < p.L.size(); ++n) + kv.push_back(p.L[n]); + for (size_t n = 0; n < p.R.size(); ++n) + kv.push_back(p.R[n]); + kv.push_back(p.a); + kv.push_back(p.b); + kv.push_back(p.t); + } + } + else { - for (size_t n = 0; n < 64; ++n) - kv.push_back(r.asig.s0[n]); - for (size_t n = 0; n < 64; ++n) - kv.push_back(r.asig.s1[n]); - kv.push_back(r.asig.ee); - for (size_t n = 0; n < 64; ++n) - kv.push_back(r.Ci[n]); + kv.reserve((64*3+1) * rv.p.rangeSigs.size()); + for (const auto &r: rv.p.rangeSigs) + { + for (size_t n = 0; n < 64; ++n) + kv.push_back(r.asig.s0[n]); + for (size_t n = 0; n < 64; ++n) + kv.push_back(r.asig.s1[n]); + kv.push_back(r.asig.ee); + for (size_t n = 0; n < 64; ++n) + kv.push_back(r.Ci[n]); + } } hashes.push_back(cn_fast_hash(kv)); return cn_fast_hash(hashes); @@ -563,7 +598,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, unsigned int index, ctkeyV &outSk) { + rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, unsigned int index, ctkeyV &outSk, bool bulletproof) { 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"); @@ -572,10 +607,13 @@ namespace rct { } rctSig rv; - rv.type = RCTTypeFull; + rv.type = bulletproof ? RCTTypeFullBulletproof : RCTTypeFull; rv.message = message; rv.outPk.resize(destinations.size()); - rv.p.rangeSigs.resize(destinations.size()); + if (bulletproof) + rv.p.bulletproofs.resize(destinations.size()); + else + rv.p.rangeSigs.resize(destinations.size()); rv.ecdhInfo.resize(destinations.size()); size_t i = 0; @@ -585,8 +623,14 @@ namespace rct { //add destination to sig rv.outPk[i].dest = copy(destinations[i]); //compute range proof - rv.p.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, amounts[i]); + 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]); #ifdef DBG + if (bulletproof) + CHECK_AND_ASSERT_THROW_MES(bulletproof_VERIFY(rv.p.bulletproofs[i]), "bulletproof_VERIFY 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"); #endif @@ -618,12 +662,12 @@ namespace rct { ctkeyM mixRing; ctkeyV outSk; tie(mixRing, index) = populateFromBlockchain(inPk, mixin); - return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, index, outSk); + return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, index, outSk, false); } //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<unsigned int> & index, ctkeyV &outSk) { + 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 bulletproof) { 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"); @@ -635,10 +679,13 @@ namespace rct { } rctSig rv; - rv.type = RCTTypeSimple; + rv.type = bulletproof ? RCTTypeSimpleBulletproof : RCTTypeSimple; rv.message = message; rv.outPk.resize(destinations.size()); - rv.p.rangeSigs.resize(destinations.size()); + if (bulletproof) + rv.p.bulletproofs.resize(destinations.size()); + else + rv.p.rangeSigs.resize(destinations.size()); rv.ecdhInfo.resize(destinations.size()); size_t i; @@ -650,10 +697,16 @@ namespace rct { //add destination to sig rv.outPk[i].dest = copy(destinations[i]); //compute range proof - rv.p.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, outamounts[i]); - #ifdef DBG - verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]); - #endif + if (bulletproof) + rv.p.bulletproofs[i] = proveRangeBulletproof(rv.outPk[i].mask, outSk[i].mask, outamounts[i]); + else + rv.p.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, outamounts[i]); + #ifdef DBG + if (bulletproof) + CHECK_AND_ASSERT_THROW_MES(bulletproof_VERIFY(rv.p.bulletproofs[i]), "bulletproof_VERIFY 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"); + #endif sc_add(sumout.bytes, outSk[i].mask.bytes, sumout.bytes); @@ -699,7 +752,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, index, outSk); + return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, amount_keys, index, outSk, false); } //RingCT protocol @@ -714,10 +767,13 @@ 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, false, "verRct called on non-full rctSig"); + CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull || rv.type == RCTTypeFullBulletproof, false, "verRct called on non-full rctSig"); if (semantics) { - CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs"); + 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.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"); } @@ -736,7 +792,10 @@ namespace rct { DP("range proofs verified?"); 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]); + if (rv.p.rangeSigs.empty()) + results[i] = bulletproof_VERIFY(rv.p.bulletproofs[i]); + else + results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]); }); } waiter.wait(); @@ -776,10 +835,13 @@ namespace rct { { PERF_TIMER(verRctSimple); - CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, false, "verRctSimple called on non simple rctSig"); + CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeSimpleBulletproof, false, "verRctSimple called on non simple rctSig"); if (semantics) { - CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs"); + if (rv.type == RCTTypeSimpleBulletproof) + 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.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"); } @@ -820,7 +882,10 @@ namespace rct { results.resize(rv.outPk.size()); 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]); + if (rv.p.rangeSigs.empty()) + results[i] = bulletproof_VERIFY(rv.p.bulletproofs[i]); + else + results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]); }); } waiter.wait(); @@ -869,9 +934,17 @@ 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) { - CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "decodeRct called on non-full rctSig"); - CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo"); + CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull || rv.type == RCTTypeFullBulletproof, false, "decodeRct called on non-full rctSig"); CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index"); + if (rv.type == RCTTypeFullBulletproof) + { + CHECK_AND_ASSERT_THROW_MES(rv.p.bulletproofs.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.p.bulletproofs and rv.ecdhInfo"); + CHECK_AND_ASSERT_THROW_MES(rv.p.bulletproofs[i].V.size() == 1, "Unexpected sizes of rv.p.bulletproofs[i].V"); + } + else + { + CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo"); + } //mask amount and mask ecdhTuple ecdh_info = rv.ecdhInfo[i]; @@ -897,16 +970,24 @@ namespace rct { } xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask) { - CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, false, "decodeRct called on non simple rctSig"); - CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo"); + CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeSimpleBulletproof, false, "decodeRct called on non simple rctSig"); CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index"); + if (rv.type == RCTTypeSimpleBulletproof) + { + CHECK_AND_ASSERT_THROW_MES(rv.p.bulletproofs.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.p.bulletproofs and rv.ecdhInfo"); + CHECK_AND_ASSERT_THROW_MES(rv.p.bulletproofs[i].V.size() == 1, "Unexpected sizes of rv.p.bulletproofs[i].V"); + } + else + { + CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo"); + } //mask amount and mask ecdhTuple ecdh_info = rv.ecdhInfo[i]; ecdhDecode(ecdh_info, sk); mask = ecdh_info.mask; key amount = ecdh_info.amount; - key C = rv.outPk[i].mask; + key C = (rv.type == RCTTypeSimpleBulletproof) ? rv.p.bulletproofs[i].V.front() : rv.outPk[i].mask; DP("C"); DP(C); key Ctmp; |