aboutsummaryrefslogtreecommitdiff
path: root/src/ringct/rctSigs.cpp
diff options
context:
space:
mode:
authorRiccardo Spagni <ric@spagni.net>2017-12-08 23:30:51 +0200
committerRiccardo Spagni <ric@spagni.net>2017-12-08 23:30:51 +0200
commit782a84f7b490baa10afef94dd6954d6ab50d020b (patch)
tree099cf5e07386236924d312606a2e4569658a1fb8 /src/ringct/rctSigs.cpp
parentMerge pull request #2845 (diff)
parentadd bulletproofs from v7 on testnet (diff)
downloadmonero-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.cpp147
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;