mirror of
https://git.wownero.com/wownero/wownero.git
synced 2025-01-08 03:18:53 +00:00
commit
389d2bc53e
@ -295,7 +295,7 @@ namespace boost
|
||||
a & x.type;
|
||||
if (x.type == rct::RCTTypeNull)
|
||||
return;
|
||||
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof)
|
||||
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeFullBulletproof && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeSimpleBulletproof && x.type != rct::RCTTypeBulletproof)
|
||||
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
|
||||
@ -323,7 +323,7 @@ namespace boost
|
||||
a & x.type;
|
||||
if (x.type == rct::RCTTypeNull)
|
||||
return;
|
||||
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof)
|
||||
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeFullBulletproof && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeSimpleBulletproof && x.type != rct::RCTTypeBulletproof)
|
||||
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
|
||||
@ -337,7 +337,7 @@ namespace boost
|
||||
if (x.p.rangeSigs.empty())
|
||||
a & x.p.bulletproofs;
|
||||
a & x.p.MGs;
|
||||
if (x.type == rct::RCTTypeBulletproof)
|
||||
if (x.type == rct::RCTTypeBulletproof || x.type == rct::RCTTypeSimpleBulletproof)
|
||||
a & x.p.pseudoOuts;
|
||||
}
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ namespace cryptonote
|
||||
if (!base_only)
|
||||
{
|
||||
const bool bulletproof = rct::is_rct_bulletproof(rv.type);
|
||||
if (bulletproof)
|
||||
if (bulletproof && rv.type == rct::RCTTypeBulletproof)
|
||||
{
|
||||
if (rv.p.bulletproofs.size() != 1)
|
||||
{
|
||||
@ -159,7 +159,7 @@ namespace cryptonote
|
||||
return false;
|
||||
}
|
||||
const size_t max_outputs = 1 << (rv.p.bulletproofs[0].L.size() - 6);
|
||||
if (max_outputs < tx.vout.size())
|
||||
if (max_outputs < tx.vout.size() && rv.type == rct::RCTTypeBulletproof)
|
||||
{
|
||||
LOG_PRINT_L1("Failed to parse transaction from blob, bad bulletproofs max outputs in tx " << get_transaction_hash(tx));
|
||||
return false;
|
||||
@ -170,6 +170,27 @@ namespace cryptonote
|
||||
for (size_t i = 0; i < n_amounts; ++i)
|
||||
rv.p.bulletproofs[0].V[i] = rct::scalarmultKey(rv.outPk[i].mask, rct::INV_EIGHT);
|
||||
}
|
||||
else if (bulletproof)
|
||||
{
|
||||
if (rct::n_bulletproof_v1_amounts(rv.p.bulletproofs) != tx.vout.size())
|
||||
{
|
||||
LOG_PRINT_L1("Failed to parse transaction from blob, bad bulletproofs size in tx " << get_transaction_hash(tx));
|
||||
return false;
|
||||
}
|
||||
size_t idx = 0;
|
||||
for (size_t n = 0; n < rv.outPk.size(); ++n)
|
||||
{
|
||||
//rv.p.bulletproofs[n].V.resize(1);
|
||||
//rv.p.bulletproofs[n].V[0] = rv.outPk[n].mask;
|
||||
CHECK_AND_ASSERT_MES(rv.p.bulletproofs[n].L.size() >= 6, false, "Bad bulletproofs L size"); // at least 64 bits
|
||||
const size_t n_amounts = rct::n_bulletproof_v1_amounts(rv.p.bulletproofs[n]);
|
||||
CHECK_AND_ASSERT_MES(idx + n_amounts <= rv.outPk.size(), false, "Internal error filling out V");
|
||||
rv.p.bulletproofs[n].V.resize(n_amounts);
|
||||
rv.p.bulletproofs[n].V.clear();
|
||||
for (size_t i = 0; i < n_amounts; ++i)
|
||||
rv.p.bulletproofs[n].V[i] = rv.outPk[idx++].mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -365,6 +386,8 @@ namespace cryptonote
|
||||
const size_t n_outputs = tx.vout.size();
|
||||
if (n_outputs <= 2)
|
||||
return blob_size;
|
||||
if (rv.type != rct::RCTTypeBulletproof)
|
||||
return blob_size;
|
||||
const uint64_t bp_base = 368;
|
||||
const size_t n_padded_outputs = rct::n_bulletproof_max_amounts(rv.p.bulletproofs);
|
||||
size_t nlr = 0;
|
||||
|
@ -2424,18 +2424,18 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
|
||||
}
|
||||
}
|
||||
|
||||
// from v11, allow bulletproofs
|
||||
if (hf_version < 11) {
|
||||
// from v8, allow bulletproofs
|
||||
if (hf_version < 8) {
|
||||
if (tx.version >= 2) {
|
||||
const bool bulletproof = rct::is_rct_bulletproof(tx.rct_signatures.type);
|
||||
if (bulletproof || !tx.rct_signatures.p.bulletproofs.empty())
|
||||
{
|
||||
MERROR_VER("New Bulletproofs are not allowed before v11");
|
||||
MERROR_VER("Bulletproofs are not allowed before v8");
|
||||
tvc.m_invalid_output = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// from v12, forbid borromean range proofs
|
||||
if (hf_version > 11) {
|
||||
@ -2448,6 +2448,20 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// from v12, forbid old bulletproofs
|
||||
if (hf_version > 11) {
|
||||
if (tx.version >= 2) {
|
||||
const bool old_bulletproof = rct::is_rct_old_bulletproof(tx.rct_signatures.type);
|
||||
if (old_bulletproof)
|
||||
{
|
||||
MERROR_VER("Old Bulletproofs are not allowed after v11");
|
||||
tvc.m_invalid_output = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -2475,7 +2489,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
|
||||
rv.message = rct::hash2rct(tx_prefix_hash);
|
||||
|
||||
// mixRing - full and simple store it in opposite ways
|
||||
if (rv.type == rct::RCTTypeFull)
|
||||
if (rv.type == rct::RCTTypeFull || rv.type == rct::RCTTypeFullBulletproof)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!pubkeys.empty() && !pubkeys[0].empty(), false, "empty pubkeys");
|
||||
rv.mixRing.resize(pubkeys[0].size());
|
||||
@ -2490,7 +2504,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof)
|
||||
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeSimpleBulletproof)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!pubkeys.empty() && !pubkeys[0].empty(), false, "empty pubkeys");
|
||||
rv.mixRing.resize(pubkeys.size());
|
||||
@ -2509,14 +2523,14 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
|
||||
}
|
||||
|
||||
// II
|
||||
if (rv.type == rct::RCTTypeFull)
|
||||
if (rv.type == rct::RCTTypeFull || rv.type == rct::RCTTypeFullBulletproof)
|
||||
{
|
||||
rv.p.MGs.resize(1);
|
||||
rv.p.MGs[0].II.resize(tx.vin.size());
|
||||
for (size_t n = 0; n < tx.vin.size(); ++n)
|
||||
rv.p.MGs[0].II[n] = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image);
|
||||
}
|
||||
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof)
|
||||
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeSimpleBulletproof)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(rv.p.MGs.size() == tx.vin.size(), false, "Bad MGs size");
|
||||
for (size_t n = 0; n < tx.vin.size(); ++n)
|
||||
@ -2789,6 +2803,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||
return false;
|
||||
}
|
||||
case rct::RCTTypeSimple:
|
||||
case rct::RCTTypeSimpleBulletproof:
|
||||
case rct::RCTTypeBulletproof:
|
||||
{
|
||||
// check all this, either reconstructed (so should really pass), or not
|
||||
@ -2847,6 +2862,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||
break;
|
||||
}
|
||||
case rct::RCTTypeFull:
|
||||
case rct::RCTTypeFullBulletproof:
|
||||
{
|
||||
// check all this, either reconstructed (so should really pass), or not
|
||||
{
|
||||
@ -2913,13 +2929,13 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||
// for bulletproofs, check they're only multi-output after v8
|
||||
if (rct::is_rct_bulletproof(rv.type))
|
||||
{
|
||||
if (hf_version < 11)
|
||||
if (hf_version < 8)
|
||||
{
|
||||
for (const rct::Bulletproof &proof: rv.p.bulletproofs)
|
||||
{
|
||||
if (proof.V.size() > 1)
|
||||
{
|
||||
MERROR_VER("Multi output bulletproofs are invalid before v11");
|
||||
MERROR_VER("Multi output bulletproofs are invalid before v8");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -711,7 +711,44 @@ namespace cryptonote
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// resolve outPk references in rct txes
|
||||
// outPk aren't the only thing that need resolving for a fully resolved tx,
|
||||
// but outPk (1) are needed now to check range proof semantics, and
|
||||
// (2) do not need access to the blockchain to find data
|
||||
if (tx.version >= 2)
|
||||
{
|
||||
rct::rctSig &rv = tx.rct_signatures;
|
||||
if (rv.type != rct::RCTTypeBulletproof){
|
||||
if (rv.outPk.size() != tx.vout.size())
|
||||
{
|
||||
LOG_PRINT_L1("WRONG TRANSACTION BLOB, Bad outPk size in tx " << tx_hash << ", rejected");
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
for (size_t n = 0; n < tx.rct_signatures.outPk.size(); ++n)
|
||||
rv.outPk[n].dest = rct::pk2rct(boost::get<txout_to_key>(tx.vout[n].target).key);
|
||||
const bool bulletproof = rct::is_rct_bulletproof(rv.type);
|
||||
if (bulletproof)
|
||||
{
|
||||
if (rct::n_bulletproof_v1_amounts(rv.p.bulletproofs) != tx.vout.size())
|
||||
{
|
||||
LOG_PRINT_L1("WRONG TRANSACTION BLOB, Bad bulletproofs size in tx " << tx_hash << ", rejected");
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
size_t idx = 0;
|
||||
for (size_t n = 0; n < rv.p.bulletproofs.size(); ++n)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(rv.p.bulletproofs[n].L.size() >= 6, false, "Bad bulletproofs L size"); // at least 64 bits
|
||||
const size_t n_amounts = rct::n_bulletproof_v1_amounts(rv.p.bulletproofs[n]);
|
||||
CHECK_AND_ASSERT_MES(idx + n_amounts <= rv.outPk.size(), false, "Internal error filling out V");
|
||||
rv.p.bulletproofs[n].V.clear();
|
||||
for (size_t i = 0; i < n_amounts; ++i)
|
||||
rv.p.bulletproofs[n].V.push_back(rv.outPk[idx++].mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
@ -770,6 +807,7 @@ namespace cryptonote
|
||||
tx_info[n].result = false;
|
||||
break;
|
||||
case rct::RCTTypeSimple:
|
||||
case rct::RCTTypeSimpleBulletproof:
|
||||
if (!rct::verRctSemanticsSimple(rv))
|
||||
{
|
||||
MERROR_VER("rct signature semantics check failed");
|
||||
@ -780,6 +818,7 @@ namespace cryptonote
|
||||
}
|
||||
break;
|
||||
case rct::RCTTypeFull:
|
||||
case rct::RCTTypeFullBulletproof:
|
||||
if (!rct::verRct(rv, true))
|
||||
{
|
||||
MERROR_VER("rct signature semantics check failed");
|
||||
|
@ -594,10 +594,12 @@ namespace cryptonote
|
||||
crypto::hash tx_prefix_hash;
|
||||
get_transaction_prefix_hash(tx, tx_prefix_hash);
|
||||
rct::ctkeyV outSk;
|
||||
if (use_simple_rct)
|
||||
if (range_proof_type != rct::RangeProofPaddedBulletproof && use_simple_rct)
|
||||
tx.rct_signatures = rct::genRctSimple_old(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, msout ? &kLRki : NULL, msout, index, outSk, range_proof_type, hwdev);
|
||||
else if (use_simple_rct && range_proof_type == rct::RangeProofPaddedBulletproof)
|
||||
tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, msout ? &kLRki : NULL, msout, index, outSk, range_proof_type, hwdev);
|
||||
else
|
||||
tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, msout ? &kLRki[0] : NULL, msout, sources[0].real_output, outSk, hwdev); // same index assumption
|
||||
tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, msout ? &kLRki[0] : NULL, msout, sources[0].real_output, outSk, range_proof_type, hwdev); // same index assumption
|
||||
memwipe(inSk.data(), inSk.size() * sizeof(rct::ctkey));
|
||||
|
||||
CHECK_AND_ASSERT_MES(tx.vout.size() == outSk.size(), false, "outSk size does not match vout");
|
||||
|
@ -82,8 +82,8 @@ namespace cryptonote
|
||||
|
||||
uint64_t get_transaction_weight_limit(uint8_t version)
|
||||
{
|
||||
// from v8, limit a tx to 50% of the minimum block weight
|
||||
if (version >= 8)
|
||||
// from v12, limit a tx to 50% of the minimum block weight
|
||||
if (version >= 12)
|
||||
return get_min_block_weight(version) / 2 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
|
||||
else
|
||||
return get_min_block_weight(version) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
|
||||
|
@ -31,7 +31,8 @@ set(ringct_basic_sources
|
||||
rctTypes.cpp
|
||||
rctCryptoOps.c
|
||||
multiexp.cc
|
||||
bulletproofs.cc)
|
||||
bulletproofs.cc
|
||||
bulletproofs2.cc)
|
||||
|
||||
set(ringct_basic_private_headers
|
||||
rctOps.h
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2017-2018, The Monero Project
|
||||
// Copyright (c) 2017-2018, The Monero And Italo Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
@ -42,10 +42,20 @@ Bulletproof bulletproof_PROVE(const rct::key &v, const rct::key &gamma);
|
||||
Bulletproof bulletproof_PROVE(uint64_t v, const rct::key &gamma);
|
||||
Bulletproof bulletproof_PROVE(const rct::keyV &v, const rct::keyV &gamma);
|
||||
Bulletproof bulletproof_PROVE(const std::vector<uint64_t> &v, const rct::keyV &gamma);
|
||||
|
||||
Bulletproof bulletproof_PROVE_old(const rct::key &v, const rct::key &gamma);
|
||||
Bulletproof bulletproof_PROVE_old(uint64_t v, const rct::key &gamma);
|
||||
Bulletproof bulletproof_PROVE_old(const rct::keyV &v, const rct::keyV &gamma);
|
||||
Bulletproof bulletproof_PROVE_old(const std::vector<uint64_t> &v, const rct::keyV &gamma);
|
||||
|
||||
bool bulletproof_VERIFY(const Bulletproof &proof);
|
||||
bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs);
|
||||
bool bulletproof_VERIFY(const std::vector<Bulletproof> &proofs);
|
||||
|
||||
bool bulletproof_VERIFY_old(const Bulletproof &proof);
|
||||
bool bulletproof_VERIFY_old(const std::vector<const Bulletproof*> &proofs);
|
||||
bool bulletproof_VERIFY_old(const std::vector<Bulletproof> &proofs);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
1160
src/ringct/bulletproofs2.cc
Normal file
1160
src/ringct/bulletproofs2.cc
Normal file
File diff suppressed because it is too large
Load Diff
@ -88,6 +88,24 @@ namespace rct {
|
||||
return proof;
|
||||
}
|
||||
|
||||
Bulletproof proveRangeBulletproof_old(key &C, key &mask, uint64_t amount)
|
||||
{
|
||||
mask = rct::skGen();
|
||||
Bulletproof proof = bulletproof_PROVE_old(amount, mask);
|
||||
CHECK_AND_ASSERT_THROW_MES(proof.V.size() == 1, "V has not exactly one element");
|
||||
C = proof.V[0];
|
||||
return proof;
|
||||
}
|
||||
|
||||
Bulletproof proveRangeBulletproof_old(keyV &C, keyV &masks, const std::vector<uint64_t> &amounts)
|
||||
{
|
||||
masks = rct::skvGen(amounts.size());
|
||||
Bulletproof proof = bulletproof_PROVE_old(amounts, masks);
|
||||
CHECK_AND_ASSERT_THROW_MES(proof.V.size() == amounts.size(), "V does not have the expected size");
|
||||
C = proof.V;
|
||||
return proof;
|
||||
}
|
||||
|
||||
bool verBulletproof(const Bulletproof &proof)
|
||||
{
|
||||
try { return bulletproof_VERIFY(proof); }
|
||||
@ -102,6 +120,20 @@ namespace rct {
|
||||
catch (...) { return false; }
|
||||
}
|
||||
|
||||
bool verBulletproof_old(const Bulletproof &proof)
|
||||
{
|
||||
try { return bulletproof_VERIFY_old(proof); }
|
||||
// we can get deep throws from ge_frombytes_vartime if input isn't valid
|
||||
catch (...) { return false; }
|
||||
}
|
||||
|
||||
bool verBulletproof_old(const std::vector<const Bulletproof*> &proofs)
|
||||
{
|
||||
try { return bulletproof_VERIFY_old(proofs); }
|
||||
// we can get deep throws from ge_frombytes_vartime if input isn't valid
|
||||
catch (...) { return false; }
|
||||
}
|
||||
|
||||
//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;
|
||||
@ -416,7 +448,7 @@ namespace rct {
|
||||
hashes.push_back(hash2rct(h));
|
||||
|
||||
keyV kv;
|
||||
if (rv.type == RCTTypeBulletproof)
|
||||
if (rv.type == RCTTypeBulletproof || rv.type == RCTTypeSimpleBulletproof || rv.type == RCTTypeFullBulletproof)
|
||||
{
|
||||
kv.reserve((6*2+9) * rv.p.bulletproofs.size());
|
||||
for (const auto &p: rv.p.bulletproofs)
|
||||
@ -677,7 +709,8 @@ 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, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, hw::device &hwdev) {
|
||||
rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, RangeProofType range_proof_type, hw::device &hwdev) {
|
||||
const bool bulletproof = range_proof_type != RangeProofBorromean;
|
||||
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");
|
||||
@ -687,10 +720,11 @@ namespace rct {
|
||||
CHECK_AND_ASSERT_THROW_MES((kLRki && msout) || (!kLRki && !msout), "Only one of kLRki/msout is present");
|
||||
|
||||
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.rangeSigs.resize(destinations.size());
|
||||
rv.ecdhInfo.resize(destinations.size());
|
||||
|
||||
size_t i = 0;
|
||||
@ -699,11 +733,46 @@ namespace rct {
|
||||
for (i = 0; i < destinations.size(); i++) {
|
||||
//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]);
|
||||
//compute range proof (bulletproofs are done later)
|
||||
if (!bulletproof)
|
||||
{
|
||||
rv.p.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, amounts[i]);
|
||||
#ifdef DBG
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
rv.p.bulletproofs.clear();
|
||||
if (bulletproof)
|
||||
{
|
||||
std::vector<uint64_t> proof_amounts;
|
||||
size_t amounts_proved = 0;
|
||||
while (amounts_proved < amounts.size())
|
||||
{
|
||||
size_t batch_size = 1;
|
||||
if (range_proof_type == RangeProofMultiOutputBulletproof)
|
||||
while (batch_size * 2 + amounts_proved <= amounts.size())
|
||||
batch_size *= 2;
|
||||
rct::keyV C, masks;
|
||||
std::vector<uint64_t> batch_amounts(batch_size);
|
||||
for (i = 0; i < batch_size; ++i)
|
||||
batch_amounts[i] = amounts[i + amounts_proved];
|
||||
rv.p.bulletproofs.push_back(proveRangeBulletproof_old(C, masks, batch_amounts));
|
||||
#ifdef DBG
|
||||
CHECK_AND_ASSERT_THROW_MES(verBulletproof_old(rv.p.bulletproofs.back()), "verBulletproof failed on newly created proof");
|
||||
#endif
|
||||
for (i = 0; i < batch_size; ++i)
|
||||
{
|
||||
rv.outPk[i + amounts_proved].mask = C[i];
|
||||
outSk[i + amounts_proved].mask = masks[i];
|
||||
}
|
||||
amounts_proved += batch_size;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < outSk.size(); ++i)
|
||||
{
|
||||
//mask amount and mask
|
||||
rv.ecdhInfo[i].mask = copy(outSk[i].mask);
|
||||
rv.ecdhInfo[i].amount = d2h(amounts[i]);
|
||||
@ -733,10 +802,10 @@ namespace rct {
|
||||
ctkeyM mixRing;
|
||||
ctkeyV outSk;
|
||||
tie(mixRing, index) = populateFromBlockchain(inPk, mixin);
|
||||
return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, kLRki, msout, index, outSk, hwdev);
|
||||
return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, kLRki, msout, index, outSk, RangeProofBorromean, hwdev);
|
||||
}
|
||||
|
||||
//RCT simple
|
||||
|
||||
//RCT simple NEW
|
||||
//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<multisig_kLRki> *kLRki, multisig_out *msout, const std::vector<unsigned int> & index, ctkeyV &outSk, RangeProofType range_proof_type, hw::device &hwdev) {
|
||||
const bool bulletproof = range_proof_type != RangeProofBorromean;
|
||||
@ -888,6 +957,104 @@ namespace rct {
|
||||
}
|
||||
return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, amount_keys, kLRki, msout, index, outSk, RangeProofBorromean, hwdev);
|
||||
}
|
||||
|
||||
//RCT simple
|
||||
//for post-rct only
|
||||
rctSig genRctSimple_old(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<multisig_kLRki> *kLRki, multisig_out *msout, const std::vector<unsigned int> & index, ctkeyV &outSk, RangeProofType range_proof_type, hw::device &hwdev) {
|
||||
const bool bulletproof = range_proof_type != RangeProofBorromean;
|
||||
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");
|
||||
CHECK_AND_ASSERT_THROW_MES(amount_keys.size() == destinations.size(), "Different number of amount_keys/destinations");
|
||||
CHECK_AND_ASSERT_THROW_MES(index.size() == inSk.size(), "Different number of index/inSk");
|
||||
CHECK_AND_ASSERT_THROW_MES(mixRing.size() == inSk.size(), "Different number of mixRing/inSk");
|
||||
for (size_t n = 0; n < mixRing.size(); ++n) {
|
||||
CHECK_AND_ASSERT_THROW_MES(index[n] < mixRing[n].size(), "Bad index into mixRing");
|
||||
}
|
||||
CHECK_AND_ASSERT_THROW_MES((kLRki && msout) || (!kLRki && !msout), "Only one of kLRki/msout is present");
|
||||
if (kLRki && msout) {
|
||||
CHECK_AND_ASSERT_THROW_MES(kLRki->size() == inamounts.size(), "Mismatched kLRki/inamounts sizes");
|
||||
}
|
||||
|
||||
rctSig rv;
|
||||
rv.type = bulletproof ? RCTTypeSimpleBulletproof : RCTTypeSimple;
|
||||
rv.message = message;
|
||||
rv.outPk.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;
|
||||
keyV masks(destinations.size()); //sk mask..
|
||||
outSk.resize(destinations.size());
|
||||
key sumout = zero();
|
||||
for (i = 0; i < destinations.size(); i++) {
|
||||
|
||||
//add destination to sig
|
||||
rv.outPk[i].dest = copy(destinations[i]);
|
||||
//compute range proof
|
||||
if (bulletproof)
|
||||
rv.p.bulletproofs[i] = proveRangeBulletproof_old(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(verBulletproof_old(rv.p.bulletproofs[i]), "verBulletproof 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);
|
||||
|
||||
//mask amount and mask
|
||||
rv.ecdhInfo[i].mask = copy(outSk[i].mask);
|
||||
rv.ecdhInfo[i].amount = d2h(outamounts[i]);
|
||||
hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i]);
|
||||
}
|
||||
|
||||
//set txn fee
|
||||
rv.txnFee = txnFee;
|
||||
// TODO: unused ??
|
||||
// key txnFeeKey = scalarmultH(d2h(rv.txnFee));
|
||||
rv.mixRing = mixRing;
|
||||
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(pseudoOuts[i], a[i], inamounts[i]);
|
||||
}
|
||||
rv.mixRing = mixRing;
|
||||
sc_sub(a[i].bytes, sumout.bytes, sumpouts.bytes);
|
||||
genC(pseudoOuts[i], a[i], inamounts[i]);
|
||||
DP(pseudoOuts[i]);
|
||||
|
||||
key full_message = get_pre_mlsag_hash(rv,hwdev);
|
||||
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], pseudoOuts[i], kLRki ? &(*kLRki)[i]: NULL, msout ? &msout->c[i] : NULL, index[i], hwdev);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
rctSig genRctSimple_old(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, xmr_amount txnFee, unsigned int mixin, hw::device &hwdev) {
|
||||
std::vector<unsigned int> index;
|
||||
index.resize(inPk.size());
|
||||
ctkeyM mixRing;
|
||||
ctkeyV outSk;
|
||||
mixRing.resize(inPk.size());
|
||||
for (size_t i = 0; i < inPk.size(); ++i) {
|
||||
mixRing[i].resize(mixin+1);
|
||||
index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin);
|
||||
}
|
||||
return genRctSimple_old(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, amount_keys, kLRki, msout, index, outSk, RangeProofBorromean, hwdev);
|
||||
}
|
||||
|
||||
//RingCT protocol
|
||||
//genRct:
|
||||
@ -901,10 +1068,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");
|
||||
const bool bulletproof = is_rct_bulletproof(rv.type);
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull || rv.type == RCTTypeFullBulletproof, false, "verRct called on non-full rctSig");
|
||||
if (semantics)
|
||||
{
|
||||
if (rv.type == RCTTypeBulletproof)
|
||||
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs");
|
||||
else
|
||||
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");
|
||||
}
|
||||
@ -919,10 +1089,21 @@ namespace rct {
|
||||
if (semantics) {
|
||||
tools::threadpool& tpool = tools::threadpool::getInstance();
|
||||
tools::threadpool::waiter waiter;
|
||||
std::deque<bool> results(rv.outPk.size(), false);
|
||||
std::deque<bool> results(bulletproof ? rv.p.bulletproofs.size() : rv.outPk.size(), false);
|
||||
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 (bulletproof && rv.type == RCTTypeBulletproof)
|
||||
{
|
||||
for (size_t i = 0; i < rv.p.bulletproofs.size(); i++)
|
||||
tpool.submit(&waiter, [&, i] { results[i] = verBulletproof(rv.p.bulletproofs[i]); });
|
||||
}
|
||||
else if (bulletproof)
|
||||
{
|
||||
for (size_t i = 0; i < rv.p.bulletproofs.size(); i++)
|
||||
tpool.submit(&waiter, [&, i] { results[i] = verBulletproof_old(rv.p.bulletproofs[i]); });
|
||||
}
|
||||
else
|
||||
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]); });
|
||||
waiter.wait(&tpool);
|
||||
|
||||
for (size_t i = 0; i < results.size(); ++i) {
|
||||
@ -976,11 +1157,12 @@ namespace rct {
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(rvp, false, "rctSig pointer is NULL");
|
||||
const rctSig &rv = *rvp;
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof, false, "verRctSemanticsSimple called on non simple rctSig");
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeSimpleBulletproof, false, "verRctSemanticsSimple called on non simple rctSig");
|
||||
const bool bulletproof = is_rct_bulletproof(rv.type);
|
||||
if (bulletproof)
|
||||
{
|
||||
if (rv.type == RCTTypeBulletproof)
|
||||
CHECK_AND_ASSERT_MES(rv.outPk.size() == n_bulletproof_amounts(rv.p.bulletproofs), false, "Mismatched sizes of outPk and bulletproofs");
|
||||
else if (bulletproof)
|
||||
{
|
||||
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");
|
||||
}
|
||||
@ -1034,12 +1216,23 @@ namespace rct {
|
||||
offset += rv.p.rangeSigs.size();
|
||||
}
|
||||
}
|
||||
if (!proofs.empty() && !verBulletproof(proofs))
|
||||
for (const rctSig *rvp: rvv)
|
||||
{
|
||||
const rctSig &rv = *rvp;
|
||||
if (rv.type != RCTTypeBulletproof){
|
||||
if (!proofs.empty() && !verBulletproof_old(proofs))
|
||||
{
|
||||
LOG_PRINT_L1("Aggregate range proof verified failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
}else{
|
||||
if (!proofs.empty() && !verBulletproof(proofs))
|
||||
{
|
||||
LOG_PRINT_L1("Aggregate range proof verified failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
waiter.wait(&tpool);
|
||||
for (size_t i = 0; i < results.size(); ++i) {
|
||||
if (!results[i]) {
|
||||
@ -1075,7 +1268,7 @@ namespace rct {
|
||||
{
|
||||
PERF_TIMER(verRctNonSemanticsSimple);
|
||||
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof, false, "verRctNonSemanticsSimple called on non simple rctSig");
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeSimpleBulletproof, false, "verRctNonSemanticsSimple called on non simple rctSig");
|
||||
const bool bulletproof = is_rct_bulletproof(rv.type);
|
||||
// semantics check is early, and mixRing/MGs aren't resolved yet
|
||||
if (bulletproof)
|
||||
@ -1135,7 +1328,7 @@ 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, hw::device &hwdev) {
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "decodeRct called on non-full rctSig");
|
||||
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");
|
||||
CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo");
|
||||
|
||||
@ -1165,7 +1358,7 @@ namespace rct {
|
||||
}
|
||||
|
||||
xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask, hw::device &hwdev) {
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof, false, "decodeRct called on non simple rctSig");
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeSimpleBulletproof, false, "decodeRct called on non simple rctSig");
|
||||
CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index");
|
||||
CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo");
|
||||
|
||||
@ -1195,12 +1388,12 @@ namespace rct {
|
||||
}
|
||||
|
||||
bool signMultisig(rctSig &rv, const std::vector<unsigned int> &indices, const keyV &k, const multisig_out &msout, const key &secret_key) {
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull || rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof,
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull || rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeFullBulletproof || rv.type == RCTTypeSimpleBulletproof,
|
||||
false, "unsupported rct type");
|
||||
CHECK_AND_ASSERT_MES(indices.size() == k.size(), false, "Mismatched k/indices sizes");
|
||||
CHECK_AND_ASSERT_MES(k.size() == rv.p.MGs.size(), false, "Mismatched k/MGs size");
|
||||
CHECK_AND_ASSERT_MES(k.size() == msout.c.size(), false, "Mismatched k/msout.c size");
|
||||
if (rv.type == RCTTypeFull)
|
||||
if (rv.type == RCTTypeFull || rv.type == RCTTypeFullBulletproof)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(rv.p.MGs.size() == 1, false, "MGs not a single element");
|
||||
}
|
||||
|
@ -119,10 +119,12 @@ namespace rct {
|
||||
//decodeRct: (c.f. https://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, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, hw::device &hwdev);
|
||||
rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const std::vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, RangeProofType range_proof_type, hw::device &hwdev);
|
||||
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 multisig_kLRki *kLRki, multisig_out *msout, const int mixin, hw::device &hwdev);
|
||||
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, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, xmr_amount txnFee, unsigned int mixin, hw::device &hwdev);
|
||||
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<multisig_kLRki> *kLRki, multisig_out *msout, const std::vector<unsigned int> & index, ctkeyV &outSk, RangeProofType range_proof_type, hw::device &hwdev);
|
||||
rctSig genRctSimple_old(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, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, xmr_amount txnFee, unsigned int mixin, hw::device &hwdev);
|
||||
rctSig genRctSimple_old(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<multisig_kLRki> *kLRki, multisig_out *msout, const std::vector<unsigned int> & index, ctkeyV &outSk, RangeProofType range_proof_type, hw::device &hwdev);
|
||||
bool verRct(const rctSig & rv, bool semantics);
|
||||
static inline bool verRct(const rctSig & rv) { return verRct(rv, true) && verRct(rv, false); }
|
||||
bool verRctSemanticsSimple(const rctSig & rv);
|
||||
@ -137,4 +139,3 @@ namespace rct {
|
||||
bool signMultisig(rctSig &rv, const std::vector<unsigned int> &indices, const keyV &k, const multisig_out &msout, const key &secret_key);
|
||||
}
|
||||
#endif /* RCTSIGS_H */
|
||||
|
||||
|
@ -216,6 +216,7 @@ namespace rct {
|
||||
switch (type)
|
||||
{
|
||||
case RCTTypeSimple:
|
||||
case RCTTypeSimpleBulletproof:
|
||||
case RCTTypeBulletproof:
|
||||
return true;
|
||||
default:
|
||||
@ -227,6 +228,8 @@ namespace rct {
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case RCTTypeSimpleBulletproof:
|
||||
case RCTTypeFullBulletproof:
|
||||
case RCTTypeBulletproof:
|
||||
return true;
|
||||
default:
|
||||
@ -234,6 +237,18 @@ namespace rct {
|
||||
}
|
||||
}
|
||||
|
||||
bool is_rct_old_bulletproof(int type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case RCTTypeSimpleBulletproof:
|
||||
case RCTTypeFullBulletproof:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_rct_borromean(int type)
|
||||
{
|
||||
switch (type)
|
||||
@ -246,6 +261,26 @@ namespace rct {
|
||||
}
|
||||
}
|
||||
|
||||
size_t n_bulletproof_v1_amounts(const Bulletproof &proof)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(proof.L.size() >= 6, 0, "Invalid bulletproof L size");
|
||||
CHECK_AND_ASSERT_MES(proof.L.size() <= 31, 0, "Insane bulletproof L size");
|
||||
return 1 << (proof.L.size() - 6);
|
||||
}
|
||||
size_t n_bulletproof_v1_amounts(const std::vector<Bulletproof> &proofs)
|
||||
{
|
||||
size_t n = 0;
|
||||
for (const Bulletproof &proof: proofs)
|
||||
{
|
||||
size_t n2 = n_bulletproof_v1_amounts(proof);
|
||||
CHECK_AND_ASSERT_MES(n2 < std::numeric_limits<uint32_t>::max() - n, 0, "Invalid number of bulletproofs");
|
||||
if (n2 == 0)
|
||||
return 0;
|
||||
n += n2;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t n_bulletproof_amounts(const Bulletproof &proof)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(proof.L.size() >= 6, 0, "Invalid bulletproof L size");
|
||||
|
@ -215,8 +215,10 @@ namespace rct {
|
||||
};
|
||||
|
||||
size_t n_bulletproof_amounts(const Bulletproof &proof);
|
||||
size_t n_bulletproof_v1_amounts(const Bulletproof &proof);
|
||||
size_t n_bulletproof_max_amounts(const Bulletproof &proof);
|
||||
size_t n_bulletproof_amounts(const std::vector<Bulletproof> &proofs);
|
||||
size_t n_bulletproof_v1_amounts(const std::vector<Bulletproof> &proofs);
|
||||
size_t n_bulletproof_max_amounts(const std::vector<Bulletproof> &proofs);
|
||||
|
||||
//A container to hold all signatures necessary for RingCT
|
||||
@ -230,7 +232,9 @@ namespace rct {
|
||||
RCTTypeNull = 0,
|
||||
RCTTypeFull = 1,
|
||||
RCTTypeSimple = 2,
|
||||
RCTTypeBulletproof = 3,
|
||||
RCTTypeFullBulletproof = 3,
|
||||
RCTTypeSimpleBulletproof = 4,
|
||||
RCTTypeBulletproof = 5,
|
||||
};
|
||||
enum RangeProofType { RangeProofBorromean, RangeProofBulletproof, RangeProofMultiOutputBulletproof, RangeProofPaddedBulletproof };
|
||||
struct rctSigBase {
|
||||
@ -249,7 +253,7 @@ namespace rct {
|
||||
FIELD(type)
|
||||
if (type == RCTTypeNull)
|
||||
return true;
|
||||
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof)
|
||||
if (type != RCTTypeFull && type != RCTTypeFullBulletproof && type != RCTTypeSimple && type != RCTTypeSimpleBulletproof && type != RCTTypeBulletproof)
|
||||
return false;
|
||||
VARINT_FIELD(txnFee)
|
||||
// inputs/outputs not saved, only here for serialization help
|
||||
@ -310,9 +314,24 @@ namespace rct {
|
||||
{
|
||||
if (type == RCTTypeNull)
|
||||
return true;
|
||||
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof)
|
||||
if (type != RCTTypeFull && type != RCTTypeFullBulletproof && type != RCTTypeSimple && type != RCTTypeSimpleBulletproof && type != RCTTypeBulletproof)
|
||||
return false;
|
||||
if (type == RCTTypeBulletproof)
|
||||
if (type == RCTTypeSimpleBulletproof || type == RCTTypeFullBulletproof)
|
||||
{
|
||||
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();
|
||||
}
|
||||
else if (type == RCTTypeBulletproof)
|
||||
{
|
||||
uint32_t nbp = bulletproofs.size();
|
||||
FIELD(nbp)
|
||||
@ -351,7 +370,7 @@ namespace rct {
|
||||
ar.begin_array();
|
||||
// we keep a byte for size of MGs, because we don't know whether this is
|
||||
// a simple or full rct signature, and it's starting to annoy the hell out of me
|
||||
size_t mg_elements = (type == RCTTypeSimple || type == RCTTypeBulletproof) ? inputs : 1;
|
||||
size_t mg_elements = (type == RCTTypeSimple || type == RCTTypeBulletproof || type == RCTTypeSimpleBulletproof) ? inputs : 1;
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_elements, MGs);
|
||||
if (MGs.size() != mg_elements)
|
||||
return false;
|
||||
@ -369,7 +388,7 @@ namespace rct {
|
||||
for (size_t j = 0; j < mixin + 1; ++j)
|
||||
{
|
||||
ar.begin_array();
|
||||
size_t mg_ss2_elements = ((type == RCTTypeSimple || type == RCTTypeBulletproof) ? 1 : inputs) + 1;
|
||||
size_t mg_ss2_elements = ((type == RCTTypeSimple || type == RCTTypeBulletproof || type == RCTTypeSimpleBulletproof) ? 1 : inputs) + 1;
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_ss2_elements, MGs[i].ss[j]);
|
||||
if (MGs[i].ss[j].size() != mg_ss2_elements)
|
||||
return false;
|
||||
@ -395,7 +414,7 @@ namespace rct {
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
if (type == RCTTypeBulletproof)
|
||||
if (type == RCTTypeBulletproof || type == RCTTypeSimpleBulletproof)
|
||||
{
|
||||
ar.tag("pseudoOuts");
|
||||
ar.begin_array();
|
||||
@ -419,12 +438,16 @@ namespace rct {
|
||||
|
||||
keyV& get_pseudo_outs()
|
||||
{
|
||||
return type == RCTTypeBulletproof ? p.pseudoOuts : pseudoOuts;
|
||||
if (type == RCTTypeBulletproof)
|
||||
return type == RCTTypeBulletproof ? p.pseudoOuts : pseudoOuts;
|
||||
return type == RCTTypeSimpleBulletproof ? p.pseudoOuts : pseudoOuts;
|
||||
}
|
||||
|
||||
keyV const& get_pseudo_outs() const
|
||||
{
|
||||
return type == RCTTypeBulletproof ? p.pseudoOuts : pseudoOuts;
|
||||
if (type == RCTTypeBulletproof)
|
||||
return type == RCTTypeBulletproof ? p.pseudoOuts : pseudoOuts;
|
||||
return type == RCTTypeSimpleBulletproof ? p.pseudoOuts : pseudoOuts;
|
||||
}
|
||||
};
|
||||
|
||||
@ -531,6 +554,7 @@ namespace rct {
|
||||
|
||||
bool is_rct_simple(int type);
|
||||
bool is_rct_bulletproof(int type);
|
||||
bool is_rct_old_bulletproof(int type);
|
||||
bool is_rct_borromean(int type);
|
||||
|
||||
static inline const rct::key &pk2rct(const crypto::public_key &pk) { return (const rct::key&)pk; }
|
||||
|
@ -2156,7 +2156,7 @@ namespace cryptonote
|
||||
return false;
|
||||
}
|
||||
|
||||
res.distributions.push_back({std::move(*data), amount, "", req.binary, req.compress});
|
||||
res.distributions.push_back({std::move(*data), amount, req.binary});
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
@ -2170,47 +2170,6 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_get_output_distribution_bin(const COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::request& req, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response& res)
|
||||
{
|
||||
PERF_TIMER(on_get_output_distribution_bin);
|
||||
|
||||
bool r;
|
||||
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUT_DISTRIBUTION>(invoke_http_mode::BIN, "/get_output_distribution.bin", req, res, r))
|
||||
return r;
|
||||
|
||||
res.status = "Failed";
|
||||
|
||||
if (!req.binary)
|
||||
{
|
||||
res.status = "Binary only call";
|
||||
return false;
|
||||
}
|
||||
try
|
||||
{
|
||||
// 0 is placeholder for the whole chain
|
||||
const uint64_t req_to_height = req.to_height ? req.to_height : (m_core.get_current_blockchain_height() - 1);
|
||||
for (uint64_t amount: req.amounts)
|
||||
{
|
||||
auto data = rpc::RpcHandler::get_output_distribution([this](uint64_t amount, uint64_t from, uint64_t to, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base) { return m_core.get_output_distribution(amount, from, to, start_height, distribution, base); }, amount, req.from_height, req_to_height, req.cumulative);
|
||||
if (!data)
|
||||
{
|
||||
res.status = "Failed to get output distribution";
|
||||
return false;
|
||||
}
|
||||
|
||||
res.distributions.push_back({std::move(*data), amount, "", req.binary, req.compress});
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
res.status = "Failed to get output distribution";
|
||||
return false;
|
||||
}
|
||||
|
||||
res.status = CORE_RPC_STATUS_OK;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
const command_line::arg_descriptor<std::string, false, true, 2> core_rpc_server::arg_rpc_bind_port = {
|
||||
|
@ -116,7 +116,6 @@ namespace cryptonote
|
||||
MAP_URI_AUTO_JON2_IF("/stop_save_graph", on_stop_save_graph, COMMAND_RPC_STOP_SAVE_GRAPH, !m_restricted)
|
||||
MAP_URI_AUTO_JON2("/get_outs", on_get_outs, COMMAND_RPC_GET_OUTPUTS)
|
||||
MAP_URI_AUTO_JON2_IF("/update", on_update, COMMAND_RPC_UPDATE, !m_restricted)
|
||||
MAP_URI_AUTO_BIN2("/get_output_distribution.bin", on_get_output_distribution_bin, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION)
|
||||
MAP_URI_AUTO_JON2_IF("/pop_blocks", on_pop_blocks, COMMAND_RPC_POP_BLOCKS, !m_restricted)
|
||||
BEGIN_JSON_RPC_MAP("/json_rpc")
|
||||
MAP_JON_RPC("get_block_count", on_getblockcount, COMMAND_RPC_GETBLOCKCOUNT)
|
||||
@ -188,7 +187,6 @@ namespace cryptonote
|
||||
bool on_start_save_graph(const COMMAND_RPC_START_SAVE_GRAPH::request& req, COMMAND_RPC_START_SAVE_GRAPH::response& res);
|
||||
bool on_stop_save_graph(const COMMAND_RPC_STOP_SAVE_GRAPH::request& req, COMMAND_RPC_STOP_SAVE_GRAPH::response& res);
|
||||
bool on_update(const COMMAND_RPC_UPDATE::request& req, COMMAND_RPC_UPDATE::response& res);
|
||||
bool on_get_output_distribution_bin(const COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::request& req, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response& res);
|
||||
bool on_pop_blocks(const COMMAND_RPC_POP_BLOCKS::request& req, COMMAND_RPC_POP_BLOCKS::response& res);
|
||||
|
||||
//json_rpc
|
||||
|
@ -34,40 +34,6 @@
|
||||
#include "cryptonote_basic/difficulty.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "rpc/rpc_handler.h"
|
||||
#include "common/varint.h"
|
||||
#include "common/perf_timer.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
template<typename T>
|
||||
std::string compress_integer_array(const std::vector<T> &v)
|
||||
{
|
||||
std::string s;
|
||||
s.resize(v.size() * (sizeof(T) * 8 / 7 + 1));
|
||||
char *ptr = (char*)s.data();
|
||||
for (const T &t: v)
|
||||
tools::write_varint(ptr, t);
|
||||
s.resize(ptr - s.data());
|
||||
return s;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> decompress_integer_array(const std::string &s)
|
||||
{
|
||||
std::vector<T> v;
|
||||
v.reserve(s.size());
|
||||
int read = 0;
|
||||
const std::string::const_iterator end = s.end();
|
||||
for (std::string::const_iterator i = s.begin(); i != end; std::advance(i, read))
|
||||
{
|
||||
T t;
|
||||
read = tools::read_varint(std::string::const_iterator(i), s.end(), t);
|
||||
CHECK_AND_ASSERT_THROW_MES(read > 0 && read <= 256, "Error decompressing data");
|
||||
v.push_back(t);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
@ -2260,7 +2226,6 @@ namespace cryptonote
|
||||
uint64_t to_height;
|
||||
bool cumulative;
|
||||
bool binary;
|
||||
bool compress;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(amounts)
|
||||
@ -2268,7 +2233,6 @@ namespace cryptonote
|
||||
KV_SERIALIZE_OPT(to_height, (uint64_t)0)
|
||||
KV_SERIALIZE_OPT(cumulative, false)
|
||||
KV_SERIALIZE_OPT(binary, true)
|
||||
KV_SERIALIZE_OPT(compress, false)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
@ -2276,38 +2240,14 @@ namespace cryptonote
|
||||
{
|
||||
rpc::output_distribution_data data;
|
||||
uint64_t amount;
|
||||
std::string compressed_data;
|
||||
bool binary;
|
||||
bool compress;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(amount)
|
||||
KV_SERIALIZE_N(data.start_height, "start_height")
|
||||
KV_SERIALIZE(binary)
|
||||
KV_SERIALIZE(compress)
|
||||
if (this_ref.binary)
|
||||
{
|
||||
if (is_store)
|
||||
{
|
||||
if (this_ref.compress)
|
||||
{
|
||||
const_cast<std::string&>(this_ref.compressed_data) = compress_integer_array(this_ref.data.distribution);
|
||||
KV_SERIALIZE(compressed_data)
|
||||
}
|
||||
else
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(data.distribution, "distribution")
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this_ref.compress)
|
||||
{
|
||||
KV_SERIALIZE(compressed_data)
|
||||
const_cast<std::vector<uint64_t>&>(this_ref.data.distribution) = decompress_integer_array<uint64_t>(this_ref.compressed_data);
|
||||
}
|
||||
else
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(data.distribution, "distribution")
|
||||
}
|
||||
}
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(data.distribution, "distribution")
|
||||
else
|
||||
KV_SERIALIZE_N(data.distribution, "distribution")
|
||||
KV_SERIALIZE_N(data.base, "base")
|
||||
|
@ -1345,9 +1345,11 @@ static uint64_t decodeRct(const rct::rctSig & rv, const crypto::key_derivation &
|
||||
switch (rv.type)
|
||||
{
|
||||
case rct::RCTTypeSimple:
|
||||
case rct::RCTTypeSimpleBulletproof:
|
||||
case rct::RCTTypeBulletproof:
|
||||
return rct::decodeRctSimple(rv, rct::sk2rct(scalar1), i, mask, hwdev);
|
||||
case rct::RCTTypeFull:
|
||||
case rct::RCTTypeFullBulletproof:
|
||||
return rct::decodeRct(rv, rct::sk2rct(scalar1), i, mask, hwdev);
|
||||
default:
|
||||
LOG_ERROR("Unsupported rct type: " << rv.type);
|
||||
@ -2900,11 +2902,10 @@ bool wallet2::get_rct_distribution(uint64_t &start_height, std::vector<uint64_t>
|
||||
cryptonote::COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response res = AUTO_VAL_INIT(res);
|
||||
req.amounts.push_back(0);
|
||||
req.from_height = 0;
|
||||
req.cumulative = false;
|
||||
req.cumulative = true;
|
||||
req.binary = true;
|
||||
req.compress = true;
|
||||
m_daemon_rpc_mutex.lock();
|
||||
bool r = net_utils::invoke_http_bin("/get_output_distribution.bin", req, res, m_http_client, rpc_timeout);
|
||||
bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_distribution", req, res, m_http_client, rpc_timeout);
|
||||
m_daemon_rpc_mutex.unlock();
|
||||
if (!r)
|
||||
{
|
||||
@ -2931,8 +2932,6 @@ bool wallet2::get_rct_distribution(uint64_t &start_height, std::vector<uint64_t>
|
||||
MWARNING("Failed to request output distribution: results are not for amount 0");
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 1; i < res.distributions[0].data.distribution.size(); ++i)
|
||||
res.distributions[0].data.distribution[i] += res.distributions[0].data.distribution[i-1];
|
||||
start_height = res.distributions[0].data.start_height;
|
||||
distribution = std::move(res.distributions[0].data.distribution);
|
||||
return true;
|
||||
@ -5676,10 +5675,15 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector<wallet2::pendin
|
||||
signed_txes.ptx.push_back(pending_tx());
|
||||
tools::wallet2::pending_tx &ptx = signed_txes.ptx.back();
|
||||
rct::RangeProofType range_proof_type = rct::RangeProofBorromean;
|
||||
if (sd.use_bulletproofs)
|
||||
const bool bulletproofv2 = use_fork_rules(11, 0);
|
||||
if (sd.use_bulletproofs && bulletproofv2)
|
||||
{
|
||||
range_proof_type = rct::RangeProofPaddedBulletproof;
|
||||
}
|
||||
else if (sd.use_bulletproofs)
|
||||
{
|
||||
range_proof_type = rct::RangeProofMultiOutputBulletproof;
|
||||
}
|
||||
crypto::secret_key tx_key;
|
||||
std::vector<crypto::secret_key> additional_tx_keys;
|
||||
rct::multisig_out msout;
|
||||
@ -6089,8 +6093,16 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto
|
||||
rct::RangeProofType range_proof_type = rct::RangeProofBorromean;
|
||||
if (sd.use_bulletproofs)
|
||||
{
|
||||
range_proof_type = rct::RangeProofPaddedBulletproof;
|
||||
}
|
||||
const bool bulletproofv2 = use_fork_rules(11, 0);
|
||||
if (bulletproofv2)
|
||||
{
|
||||
range_proof_type = rct::RangeProofPaddedBulletproof;
|
||||
}
|
||||
else
|
||||
{
|
||||
range_proof_type = rct::RangeProofMultiOutputBulletproof;
|
||||
}
|
||||
}
|
||||
bool r = cryptonote::construct_tx_with_tx_key(m_account.get_keys(), m_subaddresses, sources, sd.splitted_dsts, ptx.change_dts.addr, sd.extra, tx, sd.unlock_time, ptx.tx_key, ptx.additional_tx_keys, sd.use_rct, range_proof_type, &msout, false);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sd.sources, sd.splitted_dsts, sd.unlock_time, m_nettype);
|
||||
|
||||
@ -6244,6 +6256,10 @@ uint64_t wallet2::get_dynamic_base_fee_estimate() const
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
uint64_t wallet2::get_base_fee() const
|
||||
{
|
||||
if (use_fork_rules(HF_VERSION_PER_BYTE_FEE))
|
||||
{
|
||||
return FEE_PER_BYTE;
|
||||
}
|
||||
if(m_light_wallet)
|
||||
{
|
||||
if (use_fork_rules(HF_VERSION_PER_BYTE_FEE))
|
||||
@ -8483,8 +8499,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||
const bool use_per_byte_fee = use_fork_rules(HF_VERSION_PER_BYTE_FEE, 0);
|
||||
const bool use_rct = use_fork_rules(4, 0);
|
||||
const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0);
|
||||
const rct::RangeProofType range_proof_type = bulletproof ? rct::RangeProofPaddedBulletproof : rct::RangeProofBorromean;
|
||||
|
||||
const bool bulletproofv2 = use_fork_rules(11, 0);
|
||||
const rct::RangeProofType range_proof_type = bulletproofv2 ? rct::RangeProofPaddedBulletproof : bulletproof ? rct::RangeProofMultiOutputBulletproof : rct::RangeProofBorromean;
|
||||
const uint64_t base_fee = get_base_fee();
|
||||
const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
|
||||
const uint64_t fee_quantization_mask = get_fee_quantization_mask();
|
||||
@ -8518,7 +8534,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||
// early out if we know we can't make it anyway
|
||||
// we could also check for being within FEE_PER_KB, but if the fee calculation
|
||||
// ever changes, this might be missed, so let this go through
|
||||
const uint64_t min_fee = (fee_multiplier * base_fee * estimate_tx_size(use_rct, 1, fake_outs_count, 2, extra.size(), bulletproof));
|
||||
const uint64_t min_fee = estimate_fee(use_per_byte_fee, use_rct, 1, fake_outs_count, 2, extra.size(), bulletproof, base_fee, fee_multiplier, fee_quantization_mask);
|
||||
uint64_t balance_subtotal = 0;
|
||||
uint64_t unlocked_balance_subtotal = 0;
|
||||
for (uint32_t index_minor : subaddr_indices)
|
||||
@ -9052,7 +9068,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
||||
const bool use_per_byte_fee = use_fork_rules(HF_VERSION_PER_BYTE_FEE);
|
||||
const bool use_rct = fake_outs_count > 0 && use_fork_rules(4, 0);
|
||||
const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0);
|
||||
const rct::RangeProofType range_proof_type = bulletproof ? rct::RangeProofPaddedBulletproof : rct::RangeProofBorromean;
|
||||
const bool bulletproofv2 = use_fork_rules(11, 0);
|
||||
const rct::RangeProofType range_proof_type = bulletproofv2 ? rct::RangeProofPaddedBulletproof : bulletproof ? rct::RangeProofMultiOutputBulletproof : rct::RangeProofBorromean;
|
||||
const uint64_t base_fee = get_base_fee();
|
||||
const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
|
||||
const uint64_t fee_quantization_mask = get_fee_quantization_mask();
|
||||
|
Loading…
Reference in New Issue
Block a user