aboutsummaryrefslogtreecommitdiff
path: root/src/ringct
diff options
context:
space:
mode:
authormoneromooo-monero <moneromooo-monero@users.noreply.github.com>2017-12-02 08:32:39 +0000
committermoneromooo-monero <moneromooo-monero@users.noreply.github.com>2017-12-08 13:48:15 +0000
commitd58835b2f611872fffa3a6551ad63c9c239ae37e (patch)
treee63471834cb3413fdd5344216c5a5877fc74674a /src/ringct
parentadd bulletproofs to the build, with basic unit tests (diff)
downloadmonero-d58835b2f611872fffa3a6551ad63c9c239ae37e.tar.xz
integrate bulletproofs into monero
Diffstat (limited to 'src/ringct')
-rw-r--r--src/ringct/bulletproofs.h33
-rw-r--r--src/ringct/rctSigs.cpp64
-rw-r--r--src/ringct/rctSigs.h4
-rw-r--r--src/ringct/rctTypes.h67
4 files changed, 113 insertions, 55 deletions
diff --git a/src/ringct/bulletproofs.h b/src/ringct/bulletproofs.h
index a1e7df7ea..aca470f47 100644
--- a/src/ringct/bulletproofs.h
+++ b/src/ringct/bulletproofs.h
@@ -33,42 +33,11 @@
#ifndef BULLETPROOFS_H
#define BULLETPROOFS_H
-#include "serialization/serialization.h"
-#include "ringct/rctOps.h"
+#include "rctTypes.h"
namespace rct
{
-struct Bulletproof
-{
- rct::key V, A, S, T1, T2;
- rct::key taux, mu;
- rct::keyV L, R;
- rct::key a, b, t;
-
- Bulletproof() {}
- Bulletproof(const rct::key &V, const rct::key &A, const rct::key &S, const rct::key &T1, const rct::key &T2, const rct::key &taux, const rct::key &mu, const rct::keyV &L, const rct::keyV &R, const rct::key &a, const rct::key &b, const rct::key &t):
- V(V), A(A), S(S), T1(T1), T2(T2), taux(taux), mu(mu), L(L), R(R), a(a), b(b), t(t) {}
-
- BEGIN_SERIALIZE_OBJECT()
- FIELD(V)
- FIELD(A)
- FIELD(S)
- FIELD(T1)
- FIELD(T2)
- FIELD(taux)
- FIELD(mu)
- FIELD(L)
- FIELD(R)
- FIELD(a)
- FIELD(b)
- FIELD(t)
-
- if (L.empty() || L.size() != R.size())
- return false;
- END_SERIALIZE()
-};
-
Bulletproof bulletproof_PROVE(const rct::key &v, const rct::key &gamma);
Bulletproof bulletproof_PROVE(uint64_t v, const rct::key &gamma);
bool bulletproof_VERIFY(const Bulletproof &proof);
diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp
index 946325367..ddd26e3ad 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,14 @@ 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);
+ C = proof.V;
+ 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;
@@ -563,7 +572,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");
@@ -585,8 +594,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 +633,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");
@@ -638,7 +653,10 @@ namespace rct {
rv.type = 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 +668,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 +723,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
@@ -717,7 +741,10 @@ namespace rct {
CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, 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.p.rangeSigs.empty())
+ 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 +763,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]); // TODO
+ else
+ results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
});
}
waiter.wait();
@@ -779,7 +809,10 @@ namespace rct {
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, 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.p.rangeSigs.empty())
+ 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 +853,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();
diff --git a/src/ringct/rctSigs.h b/src/ringct/rctSigs.h
index d158f06f0..46c9cb2df 100644
--- a/src/ringct/rctSigs.h
+++ b/src/ringct/rctSigs.h
@@ -118,10 +118,10 @@ namespace rct {
//decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1)
// 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
- rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const std::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 std::vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, unsigned int index, ctkeyV &outSk, bool bulletproof);
rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector<xmr_amount> & amounts, const keyV &amount_keys, const int mixin);
rctSig genRctSimple(const key & message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector<xmr_amount> & inamounts, const std::vector<xmr_amount> & outamounts, const keyV &amount_keys, xmr_amount txnFee, unsigned int mixin);
- rctSig genRctSimple(const key & message, const ctkeyV & inSk, const keyV & destinations, const std::vector<xmr_amount> & inamounts, const std::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 std::vector<xmr_amount> & inamounts, const std::vector<xmr_amount> & outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<unsigned int> & index, ctkeyV &outSk, bool bulletproof);
bool verRct(const rctSig & rv, bool semantics);
static inline bool verRct(const rctSig & rv) { return verRct(rv, true) && verRct(rv, false); }
bool verRctSimple(const rctSig & rv, bool semantics);
diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h
index 8147cb602..aa906c0ef 100644
--- a/src/ringct/rctTypes.h
+++ b/src/ringct/rctTypes.h
@@ -161,6 +161,37 @@ namespace rct {
FIELD(Ci)
END_SERIALIZE()
};
+
+ struct Bulletproof
+ {
+ rct::key V, A, S, T1, T2;
+ rct::key taux, mu;
+ rct::keyV L, R;
+ rct::key a, b, t;
+
+ Bulletproof() {}
+ Bulletproof(const rct::key &V, const rct::key &A, const rct::key &S, const rct::key &T1, const rct::key &T2, const rct::key &taux, const rct::key &mu, const rct::keyV &L, const rct::keyV &R, const rct::key &a, const rct::key &b, const rct::key &t):
+ V(V), A(A), S(S), T1(T1), T2(T2), taux(taux), mu(mu), L(L), R(R), a(a), b(b), t(t) {}
+
+ BEGIN_SERIALIZE_OBJECT()
+ FIELD(V)
+ FIELD(A)
+ FIELD(S)
+ FIELD(T1)
+ FIELD(T2)
+ FIELD(taux)
+ FIELD(mu)
+ FIELD(L)
+ FIELD(R)
+ FIELD(a)
+ FIELD(b)
+ FIELD(t)
+
+ if (L.empty() || L.size() != R.size())
+ return false;
+ END_SERIALIZE()
+ };
+
//A container to hold all signatures necessary for RingCT
// rangeSigs holds all the rangeproof data of a transaction
// MG holds the MLSAG signature of a transaction
@@ -241,6 +272,7 @@ namespace rct {
};
struct rctSigPrunable {
std::vector<rangeSig> rangeSigs;
+ std::vector<Bulletproof> bulletproofs;
std::vector<mgSig> MGs; // simple rct has N, full has 1
template<bool W, template <bool> class Archive>
@@ -253,15 +285,33 @@ namespace rct {
ar.tag("rangeSigs");
ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, rangeSigs);
- if (rangeSigs.size() != outputs)
- return false;
- for (size_t i = 0; i < outputs; ++i)
+ if (!rangeSigs.empty())
{
- FIELDS(rangeSigs[i])
- if (outputs - i > 1)
- ar.delimit_array();
+ if (rangeSigs.size() != outputs)
+ return false;
+ for (size_t i = 0; i < outputs; ++i)
+ {
+ FIELDS(rangeSigs[i])
+ if (outputs - i > 1)
+ ar.delimit_array();
+ }
+ ar.end_array();
+ }
+ else
+ {
+ ar.tag("bp");
+ ar.begin_array();
+ PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, bulletproofs);
+ if (bulletproofs.size() != outputs)
+ return false;
+ for (size_t i = 0; i < outputs; ++i)
+ {
+ FIELDS(bulletproofs[i])
+ if (outputs - i > 1)
+ ar.delimit_array();
+ }
+ ar.end_array();
}
- ar.end_array();
ar.tag("MGs");
ar.begin_array();
@@ -464,6 +514,7 @@ VARIANT_TAG(debug_archive, rct::mgSig, "rct::mgSig");
VARIANT_TAG(debug_archive, rct::rangeSig, "rct::rangeSig");
VARIANT_TAG(debug_archive, rct::boroSig, "rct::boroSig");
VARIANT_TAG(debug_archive, rct::rctSig, "rct::rctSig");
+VARIANT_TAG(debug_archive, rct::Bulletproof, "rct::bulletproof");
VARIANT_TAG(binary_archive, rct::key, 0x90);
VARIANT_TAG(binary_archive, rct::key64, 0x91);
@@ -477,6 +528,7 @@ VARIANT_TAG(binary_archive, rct::mgSig, 0x98);
VARIANT_TAG(binary_archive, rct::rangeSig, 0x99);
VARIANT_TAG(binary_archive, rct::boroSig, 0x9a);
VARIANT_TAG(binary_archive, rct::rctSig, 0x9b);
+VARIANT_TAG(binary_archive, rct::Bulletproof, 0x9c);
VARIANT_TAG(json_archive, rct::key, "rct_key");
VARIANT_TAG(json_archive, rct::key64, "rct_key64");
@@ -490,5 +542,6 @@ VARIANT_TAG(json_archive, rct::mgSig, "rct_mgSig");
VARIANT_TAG(json_archive, rct::rangeSig, "rct_rangeSig");
VARIANT_TAG(json_archive, rct::boroSig, "rct_boroSig");
VARIANT_TAG(json_archive, rct::rctSig, "rct_rctSig");
+VARIANT_TAG(json_archive, rct::Bulletproof, "rct_bulletproof");
#endif /* RCTTYPES_H */