integrate bulletproofs into monero
This commit is contained in:
parent
90b8d9f271
commit
d58835b2f6
|
@ -211,6 +211,23 @@ namespace boost
|
||||||
a & x.Ci;
|
a & x.Ci;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class Archive>
|
||||||
|
inline void serialize(Archive &a, rct::Bulletproof &x, const boost::serialization::version_type ver)
|
||||||
|
{
|
||||||
|
a & x.V;
|
||||||
|
a & x.A;
|
||||||
|
a & x.S;
|
||||||
|
a & x.T1;
|
||||||
|
a & x.T2;
|
||||||
|
a & x.taux;
|
||||||
|
a & x.mu;
|
||||||
|
a & x.L;
|
||||||
|
a & x.R;
|
||||||
|
a & x.a;
|
||||||
|
a & x.b;
|
||||||
|
a & x.t;
|
||||||
|
}
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
inline void serialize(Archive &a, rct::boroSig &x, const boost::serialization::version_type ver)
|
inline void serialize(Archive &a, rct::boroSig &x, const boost::serialization::version_type ver)
|
||||||
{
|
{
|
||||||
|
@ -278,6 +295,8 @@ namespace boost
|
||||||
inline void serialize(Archive &a, rct::rctSigPrunable &x, const boost::serialization::version_type ver)
|
inline void serialize(Archive &a, rct::rctSigPrunable &x, const boost::serialization::version_type ver)
|
||||||
{
|
{
|
||||||
a & x.rangeSigs;
|
a & x.rangeSigs;
|
||||||
|
if (x.rangeSigs.empty())
|
||||||
|
a & x.bulletproofs;
|
||||||
a & x.MGs;
|
a & x.MGs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,6 +317,8 @@ namespace boost
|
||||||
a & x.txnFee;
|
a & x.txnFee;
|
||||||
//--------------
|
//--------------
|
||||||
a & x.p.rangeSigs;
|
a & x.p.rangeSigs;
|
||||||
|
if (x.p.rangeSigs.empty())
|
||||||
|
a & x.p.bulletproofs;
|
||||||
a & x.p.MGs;
|
a & x.p.MGs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,7 +160,7 @@ namespace cryptonote
|
||||||
return destinations[0].addr.m_view_public_key;
|
return destinations[0].addr.m_view_public_key;
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct)
|
bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct, bool bulletproof)
|
||||||
{
|
{
|
||||||
std::vector<rct::key> amount_keys;
|
std::vector<rct::key> amount_keys;
|
||||||
tx.set_null();
|
tx.set_null();
|
||||||
|
@ -552,9 +552,9 @@ namespace cryptonote
|
||||||
get_transaction_prefix_hash(tx, tx_prefix_hash);
|
get_transaction_prefix_hash(tx, tx_prefix_hash);
|
||||||
rct::ctkeyV outSk;
|
rct::ctkeyV outSk;
|
||||||
if (use_simple_rct)
|
if (use_simple_rct)
|
||||||
tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, index, outSk);
|
tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, index, outSk, bulletproof);
|
||||||
else
|
else
|
||||||
tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, sources[0].real_output, outSk); // same index assumption
|
tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, sources[0].real_output, outSk, bulletproof); // same index assumption
|
||||||
|
|
||||||
CHECK_AND_ASSERT_MES(tx.vout.size() == outSk.size(), false, "outSk size does not match vout");
|
CHECK_AND_ASSERT_MES(tx.vout.size() == outSk.size(), false, "outSk size does not match vout");
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,7 @@ namespace cryptonote
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const account_keys &sender_keys);
|
crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const account_keys &sender_keys);
|
||||||
bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time);
|
bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time);
|
||||||
bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false);
|
bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, bool bulletproof = false);
|
||||||
|
|
||||||
bool generate_genesis_block(
|
bool generate_genesis_block(
|
||||||
block& bl
|
block& bl
|
||||||
|
|
|
@ -33,42 +33,11 @@
|
||||||
#ifndef BULLETPROOFS_H
|
#ifndef BULLETPROOFS_H
|
||||||
#define BULLETPROOFS_H
|
#define BULLETPROOFS_H
|
||||||
|
|
||||||
#include "serialization/serialization.h"
|
#include "rctTypes.h"
|
||||||
#include "ringct/rctOps.h"
|
|
||||||
|
|
||||||
namespace rct
|
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(const rct::key &v, const rct::key &gamma);
|
||||||
Bulletproof bulletproof_PROVE(uint64_t v, const rct::key &gamma);
|
Bulletproof bulletproof_PROVE(uint64_t v, const rct::key &gamma);
|
||||||
bool bulletproof_VERIFY(const Bulletproof &proof);
|
bool bulletproof_VERIFY(const Bulletproof &proof);
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "common/threadpool.h"
|
#include "common/threadpool.h"
|
||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
#include "rctSigs.h"
|
#include "rctSigs.h"
|
||||||
|
#include "bulletproofs.h"
|
||||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||||
|
|
||||||
using namespace crypto;
|
using namespace crypto;
|
||||||
|
@ -42,6 +43,14 @@ using namespace std;
|
||||||
#define MONERO_DEFAULT_LOG_CATEGORY "ringct"
|
#define MONERO_DEFAULT_LOG_CATEGORY "ringct"
|
||||||
|
|
||||||
namespace rct {
|
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)
|
//Borromean (c.f. gmax/andytoshi's paper)
|
||||||
boroSig genBorromean(const key64 x, const key64 P1, const key64 P2, const bits indices) {
|
boroSig genBorromean(const key64 x, const key64 P1, const key64 P2, const bits indices) {
|
||||||
key64 L[2], alpha;
|
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
|
// 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
|
// 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
|
// 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(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(amount_keys.size() == destinations.size(), "Different number of amount_keys/destinations");
|
||||||
CHECK_AND_ASSERT_THROW_MES(index < mixRing.size(), "Bad index into mixRing");
|
CHECK_AND_ASSERT_THROW_MES(index < mixRing.size(), "Bad index into mixRing");
|
||||||
|
@ -585,8 +594,14 @@ namespace rct {
|
||||||
//add destination to sig
|
//add destination to sig
|
||||||
rv.outPk[i].dest = copy(destinations[i]);
|
rv.outPk[i].dest = copy(destinations[i]);
|
||||||
//compute range proof
|
//compute range proof
|
||||||
|
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]);
|
rv.p.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, amounts[i]);
|
||||||
#ifdef DBG
|
#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");
|
CHECK_AND_ASSERT_THROW_MES(verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]), "verRange failed on newly created proof");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -618,12 +633,12 @@ namespace rct {
|
||||||
ctkeyM mixRing;
|
ctkeyM mixRing;
|
||||||
ctkeyV outSk;
|
ctkeyV outSk;
|
||||||
tie(mixRing, index) = populateFromBlockchain(inPk, mixin);
|
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
|
//RCT simple
|
||||||
//for post-rct only
|
//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() > 0, "Empty inamounts");
|
||||||
CHECK_AND_ASSERT_THROW_MES(inamounts.size() == inSk.size(), "Different number of inamounts/inSk");
|
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");
|
CHECK_AND_ASSERT_THROW_MES(outamounts.size() == destinations.size(), "Different number of amounts/destinations");
|
||||||
|
@ -638,6 +653,9 @@ namespace rct {
|
||||||
rv.type = RCTTypeSimple;
|
rv.type = RCTTypeSimple;
|
||||||
rv.message = message;
|
rv.message = message;
|
||||||
rv.outPk.resize(destinations.size());
|
rv.outPk.resize(destinations.size());
|
||||||
|
if (bulletproof)
|
||||||
|
rv.p.bulletproofs.resize(destinations.size());
|
||||||
|
else
|
||||||
rv.p.rangeSigs.resize(destinations.size());
|
rv.p.rangeSigs.resize(destinations.size());
|
||||||
rv.ecdhInfo.resize(destinations.size());
|
rv.ecdhInfo.resize(destinations.size());
|
||||||
|
|
||||||
|
@ -650,9 +668,15 @@ namespace rct {
|
||||||
//add destination to sig
|
//add destination to sig
|
||||||
rv.outPk[i].dest = copy(destinations[i]);
|
rv.outPk[i].dest = copy(destinations[i]);
|
||||||
//compute range proof
|
//compute range proof
|
||||||
|
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]);
|
rv.p.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, outamounts[i]);
|
||||||
#ifdef DBG
|
#ifdef DBG
|
||||||
verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
|
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
|
#endif
|
||||||
|
|
||||||
sc_add(sumout.bytes, outSk[i].mask.bytes, sumout.bytes);
|
sc_add(sumout.bytes, outSk[i].mask.bytes, sumout.bytes);
|
||||||
|
@ -699,7 +723,7 @@ namespace rct {
|
||||||
mixRing[i].resize(mixin+1);
|
mixRing[i].resize(mixin+1);
|
||||||
index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin);
|
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
|
//RingCT protocol
|
||||||
|
@ -717,6 +741,9 @@ namespace rct {
|
||||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "verRct called on non-full rctSig");
|
CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "verRct called on non-full rctSig");
|
||||||
if (semantics)
|
if (semantics)
|
||||||
{
|
{
|
||||||
|
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.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.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");
|
CHECK_AND_ASSERT_MES(rv.p.MGs.size() == 1, false, "full rctSig has not one MG");
|
||||||
|
@ -736,6 +763,9 @@ namespace rct {
|
||||||
DP("range proofs verified?");
|
DP("range proofs verified?");
|
||||||
for (size_t i = 0; i < rv.outPk.size(); i++) {
|
for (size_t i = 0; i < rv.outPk.size(); i++) {
|
||||||
tpool.submit(&waiter, [&, i] {
|
tpool.submit(&waiter, [&, 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]);
|
results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -779,6 +809,9 @@ namespace rct {
|
||||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, false, "verRctSimple called on non simple rctSig");
|
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, false, "verRctSimple called on non simple rctSig");
|
||||||
if (semantics)
|
if (semantics)
|
||||||
{
|
{
|
||||||
|
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.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.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");
|
CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.p.MGs.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.p.MGs");
|
||||||
|
@ -820,6 +853,9 @@ namespace rct {
|
||||||
results.resize(rv.outPk.size());
|
results.resize(rv.outPk.size());
|
||||||
for (size_t i = 0; i < rv.outPk.size(); i++) {
|
for (size_t i = 0; i < rv.outPk.size(); i++) {
|
||||||
tpool.submit(&waiter, [&, i] {
|
tpool.submit(&waiter, [&, 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]);
|
results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,10 +118,10 @@ namespace rct {
|
||||||
//decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1)
|
//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
|
// 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
|
// 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 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 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);
|
bool verRct(const rctSig & rv, bool semantics);
|
||||||
static inline bool verRct(const rctSig & rv) { return verRct(rv, true) && verRct(rv, false); }
|
static inline bool verRct(const rctSig & rv) { return verRct(rv, true) && verRct(rv, false); }
|
||||||
bool verRctSimple(const rctSig & rv, bool semantics);
|
bool verRctSimple(const rctSig & rv, bool semantics);
|
||||||
|
|
|
@ -161,6 +161,37 @@ namespace rct {
|
||||||
FIELD(Ci)
|
FIELD(Ci)
|
||||||
END_SERIALIZE()
|
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
|
//A container to hold all signatures necessary for RingCT
|
||||||
// rangeSigs holds all the rangeproof data of a transaction
|
// rangeSigs holds all the rangeproof data of a transaction
|
||||||
// MG holds the MLSAG signature of a transaction
|
// MG holds the MLSAG signature of a transaction
|
||||||
|
@ -241,6 +272,7 @@ namespace rct {
|
||||||
};
|
};
|
||||||
struct rctSigPrunable {
|
struct rctSigPrunable {
|
||||||
std::vector<rangeSig> rangeSigs;
|
std::vector<rangeSig> rangeSigs;
|
||||||
|
std::vector<Bulletproof> bulletproofs;
|
||||||
std::vector<mgSig> MGs; // simple rct has N, full has 1
|
std::vector<mgSig> MGs; // simple rct has N, full has 1
|
||||||
|
|
||||||
template<bool W, template <bool> class Archive>
|
template<bool W, template <bool> class Archive>
|
||||||
|
@ -253,6 +285,8 @@ namespace rct {
|
||||||
ar.tag("rangeSigs");
|
ar.tag("rangeSigs");
|
||||||
ar.begin_array();
|
ar.begin_array();
|
||||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, rangeSigs);
|
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, rangeSigs);
|
||||||
|
if (!rangeSigs.empty())
|
||||||
|
{
|
||||||
if (rangeSigs.size() != outputs)
|
if (rangeSigs.size() != outputs)
|
||||||
return false;
|
return false;
|
||||||
for (size_t i = 0; i < outputs; ++i)
|
for (size_t i = 0; i < outputs; ++i)
|
||||||
|
@ -262,6 +296,22 @@ namespace rct {
|
||||||
ar.delimit_array();
|
ar.delimit_array();
|
||||||
}
|
}
|
||||||
ar.end_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.tag("MGs");
|
ar.tag("MGs");
|
||||||
ar.begin_array();
|
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::rangeSig, "rct::rangeSig");
|
||||||
VARIANT_TAG(debug_archive, rct::boroSig, "rct::boroSig");
|
VARIANT_TAG(debug_archive, rct::boroSig, "rct::boroSig");
|
||||||
VARIANT_TAG(debug_archive, rct::rctSig, "rct::rctSig");
|
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::key, 0x90);
|
||||||
VARIANT_TAG(binary_archive, rct::key64, 0x91);
|
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::rangeSig, 0x99);
|
||||||
VARIANT_TAG(binary_archive, rct::boroSig, 0x9a);
|
VARIANT_TAG(binary_archive, rct::boroSig, 0x9a);
|
||||||
VARIANT_TAG(binary_archive, rct::rctSig, 0x9b);
|
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::key, "rct_key");
|
||||||
VARIANT_TAG(json_archive, rct::key64, "rct_key64");
|
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::rangeSig, "rct_rangeSig");
|
||||||
VARIANT_TAG(json_archive, rct::boroSig, "rct_boroSig");
|
VARIANT_TAG(json_archive, rct::boroSig, "rct_boroSig");
|
||||||
VARIANT_TAG(json_archive, rct::rctSig, "rct_rctSig");
|
VARIANT_TAG(json_archive, rct::rctSig, "rct_rctSig");
|
||||||
|
VARIANT_TAG(json_archive, rct::Bulletproof, "rct_bulletproof");
|
||||||
|
|
||||||
#endif /* RCTTYPES_H */
|
#endif /* RCTTYPES_H */
|
||||||
|
|
|
@ -456,7 +456,7 @@ void drop_from_short_history(std::list<crypto::hash> &short_chain_history, size_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra_size)
|
size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof)
|
||||||
{
|
{
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
|
|
||||||
|
@ -480,6 +480,9 @@ size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra
|
||||||
size += 1;
|
size += 1;
|
||||||
|
|
||||||
// rangeSigs
|
// rangeSigs
|
||||||
|
if (bulletproof)
|
||||||
|
size += ((2*6 + 4 + 5)*32 + 3) * n_outputs;
|
||||||
|
else
|
||||||
size += (2*64*32+32+64*32) * n_outputs;
|
size += (2*64*32+32+64*32) * n_outputs;
|
||||||
|
|
||||||
// MGs
|
// MGs
|
||||||
|
@ -501,14 +504,22 @@ size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t estimate_tx_size(bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size)
|
size_t estimate_tx_size(bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof)
|
||||||
{
|
{
|
||||||
if (use_rct)
|
if (use_rct)
|
||||||
return estimate_rct_tx_size(n_inputs, mixin, n_outputs + 1, extra_size);
|
return estimate_rct_tx_size(n_inputs, mixin, n_outputs + 1, extra_size, bulletproof);
|
||||||
else
|
else
|
||||||
return n_inputs * (mixin+1) * APPROXIMATE_INPUT_BYTES + extra_size;
|
return n_inputs * (mixin+1) * APPROXIMATE_INPUT_BYTES + extra_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t get_bulletproof_fork(bool testnet)
|
||||||
|
{
|
||||||
|
if (testnet)
|
||||||
|
return 7;
|
||||||
|
else
|
||||||
|
return 255; // TODO
|
||||||
|
}
|
||||||
|
|
||||||
} //namespace
|
} //namespace
|
||||||
|
|
||||||
namespace tools
|
namespace tools
|
||||||
|
@ -4066,7 +4077,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<crypto
|
||||||
pending_tx ptx;
|
pending_tx ptx;
|
||||||
|
|
||||||
// loop until fee is met without increasing tx size to next KB boundary.
|
// loop until fee is met without increasing tx size to next KB boundary.
|
||||||
const size_t estimated_tx_size = estimate_tx_size(false, unused_transfers_indices.size(), fake_outs_count, dst_vector.size(), extra.size());
|
const size_t estimated_tx_size = estimate_tx_size(false, unused_transfers_indices.size(), fake_outs_count, dst_vector.size(), extra.size(), false);
|
||||||
uint64_t needed_fee = calculate_fee(fee_per_kb, estimated_tx_size, fee_multiplier);
|
uint64_t needed_fee = calculate_fee(fee_per_kb, estimated_tx_size, fee_multiplier);
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -5432,6 +5443,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||||
uint64_t needed_fee, available_for_fee = 0;
|
uint64_t needed_fee, available_for_fee = 0;
|
||||||
uint64_t upper_transaction_size_limit = get_upper_transaction_size_limit();
|
uint64_t upper_transaction_size_limit = get_upper_transaction_size_limit();
|
||||||
const bool use_rct = use_fork_rules(4, 0);
|
const bool use_rct = use_fork_rules(4, 0);
|
||||||
|
const bool bulletproof = use_fork_rules(get_bulletproof_fork(m_testnet), 0);
|
||||||
|
|
||||||
const uint64_t fee_per_kb = get_per_kb_fee();
|
const uint64_t fee_per_kb = get_per_kb_fee();
|
||||||
const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
|
const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
|
||||||
|
@ -5567,7 +5579,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||||
{
|
{
|
||||||
// this is used to build a tx that's 1 or 2 inputs, and 2 outputs, which
|
// this is used to build a tx that's 1 or 2 inputs, and 2 outputs, which
|
||||||
// will get us a known fee.
|
// will get us a known fee.
|
||||||
uint64_t estimated_fee = calculate_fee(fee_per_kb, estimate_rct_tx_size(2, fake_outs_count, 2, extra.size()), fee_multiplier);
|
uint64_t estimated_fee = calculate_fee(fee_per_kb, estimate_rct_tx_size(2, fake_outs_count, 2, extra.size(), bulletproof), fee_multiplier);
|
||||||
preferred_inputs = pick_preferred_rct_inputs(needed_money + estimated_fee, subaddr_account, subaddr_indices);
|
preferred_inputs = pick_preferred_rct_inputs(needed_money + estimated_fee, subaddr_account, subaddr_indices);
|
||||||
if (!preferred_inputs.empty())
|
if (!preferred_inputs.empty())
|
||||||
{
|
{
|
||||||
|
@ -5670,7 +5682,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while (!dsts.empty() && dsts[0].amount <= available_amount && estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size()) < TX_SIZE_TARGET(upper_transaction_size_limit))
|
while (!dsts.empty() && dsts[0].amount <= available_amount && estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof) < TX_SIZE_TARGET(upper_transaction_size_limit))
|
||||||
{
|
{
|
||||||
// we can fully pay that destination
|
// we can fully pay that destination
|
||||||
LOG_PRINT_L2("We can fully pay " << get_account_address_as_str(m_testnet, dsts[0].is_subaddress, dsts[0].addr) <<
|
LOG_PRINT_L2("We can fully pay " << get_account_address_as_str(m_testnet, dsts[0].is_subaddress, dsts[0].addr) <<
|
||||||
|
@ -5682,7 +5694,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||||
++original_output_index;
|
++original_output_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (available_amount > 0 && !dsts.empty() && estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size()) < TX_SIZE_TARGET(upper_transaction_size_limit)) {
|
if (available_amount > 0 && !dsts.empty() && estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof) < TX_SIZE_TARGET(upper_transaction_size_limit)) {
|
||||||
// we can partially fill that destination
|
// we can partially fill that destination
|
||||||
LOG_PRINT_L2("We can partially pay " << get_account_address_as_str(m_testnet, dsts[0].is_subaddress, dsts[0].addr) <<
|
LOG_PRINT_L2("We can partially pay " << get_account_address_as_str(m_testnet, dsts[0].is_subaddress, dsts[0].addr) <<
|
||||||
" for " << print_money(available_amount) << "/" << print_money(dsts[0].amount));
|
" for " << print_money(available_amount) << "/" << print_money(dsts[0].amount));
|
||||||
|
@ -5706,7 +5718,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const size_t estimated_rct_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size());
|
const size_t estimated_rct_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof);
|
||||||
try_tx = dsts.empty() || (estimated_rct_tx_size >= TX_SIZE_TARGET(upper_transaction_size_limit));
|
try_tx = dsts.empty() || (estimated_rct_tx_size >= TX_SIZE_TARGET(upper_transaction_size_limit));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5715,7 +5727,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||||
cryptonote::transaction test_tx;
|
cryptonote::transaction test_tx;
|
||||||
pending_tx test_ptx;
|
pending_tx test_ptx;
|
||||||
|
|
||||||
const size_t estimated_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size());
|
const size_t estimated_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof);
|
||||||
needed_fee = calculate_fee(fee_per_kb, estimated_tx_size, fee_multiplier);
|
needed_fee = calculate_fee(fee_per_kb, estimated_tx_size, fee_multiplier);
|
||||||
|
|
||||||
LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " outputs and " <<
|
LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " outputs and " <<
|
||||||
|
@ -5917,6 +5929,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
||||||
std::vector<std::vector<get_outs_entry>> outs;
|
std::vector<std::vector<get_outs_entry>> outs;
|
||||||
|
|
||||||
const bool use_rct = fake_outs_count > 0 && use_fork_rules(4, 0);
|
const bool use_rct = fake_outs_count > 0 && use_fork_rules(4, 0);
|
||||||
|
const bool bulletproof = use_fork_rules(get_bulletproof_fork(m_testnet), 0);
|
||||||
const uint64_t fee_per_kb = get_per_kb_fee();
|
const uint64_t fee_per_kb = get_per_kb_fee();
|
||||||
const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
|
const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
|
||||||
|
|
||||||
|
@ -5955,14 +5968,14 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
||||||
// here, check if we need to sent tx and start a new one
|
// here, check if we need to sent tx and start a new one
|
||||||
LOG_PRINT_L2("Considering whether to create a tx now, " << tx.selected_transfers.size() << " inputs, tx limit "
|
LOG_PRINT_L2("Considering whether to create a tx now, " << tx.selected_transfers.size() << " inputs, tx limit "
|
||||||
<< upper_transaction_size_limit);
|
<< upper_transaction_size_limit);
|
||||||
const size_t estimated_rct_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size() + 1, extra.size());
|
const size_t estimated_rct_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size() + 1, extra.size(), bulletproof);
|
||||||
bool try_tx = (unused_dust_indices.empty() && unused_transfers_indices.empty()) || ( estimated_rct_tx_size >= TX_SIZE_TARGET(upper_transaction_size_limit));
|
bool try_tx = (unused_dust_indices.empty() && unused_transfers_indices.empty()) || ( estimated_rct_tx_size >= TX_SIZE_TARGET(upper_transaction_size_limit));
|
||||||
|
|
||||||
if (try_tx) {
|
if (try_tx) {
|
||||||
cryptonote::transaction test_tx;
|
cryptonote::transaction test_tx;
|
||||||
pending_tx test_ptx;
|
pending_tx test_ptx;
|
||||||
|
|
||||||
const size_t estimated_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size());
|
const size_t estimated_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof);
|
||||||
needed_fee = calculate_fee(fee_per_kb, estimated_tx_size, fee_multiplier);
|
needed_fee = calculate_fee(fee_per_kb, estimated_tx_size, fee_multiplier);
|
||||||
|
|
||||||
tx.dsts.push_back(tx_destination_entry(1, address, is_subaddress));
|
tx.dsts.push_back(tx_destination_entry(1, address, is_subaddress));
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
#include "ringct/rctOps.h"
|
||||||
#include "ringct/bulletproofs.h"
|
#include "ringct/bulletproofs.h"
|
||||||
|
|
||||||
TEST(bulletproofs, valid_zero)
|
TEST(bulletproofs, valid_zero)
|
||||||
|
|
Loading…
Reference in New Issue