cleanup old bp

This commit is contained in:
wowario
2023-02-03 01:14:11 +03:00
committed by nahuhh
parent 7e00405190
commit 2f48099996
26 changed files with 1725 additions and 134 deletions

View File

@@ -241,8 +241,15 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const std::pair
} }
else else
{ {
rct::key commitment;
if (tx.version > 1)
{
commitment = tx.rct_signatures.outPk[i].mask;
if (rct::is_rct_bp_plus_legacy(tx.rct_signatures.type))
commitment = rct::scalarmult8(commitment);
}
amount_output_indices[i] = add_output(tx_hash, tx.vout[i], i, tx.unlock_time, amount_output_indices[i] = add_output(tx_hash, tx.vout[i], i, tx.unlock_time,
tx.version > 1 ? &tx.rct_signatures.outPk[i].mask : NULL); tx.version > 1 ? &commitment : NULL);
} }
} }
add_tx_amount_output_indices(tx_id, amount_output_indices); add_tx_amount_output_indices(tx_id, amount_output_indices);

View File

@@ -335,7 +335,7 @@ namespace boost
a & x.type; a & x.type;
if (x.type == rct::RCTTypeNull) if (x.type == rct::RCTTypeNull)
return; return;
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2 && x.type != rct::RCTTypeCLSAG && x.type != rct::RCTTypeBulletproofPlus) if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2 && x.type != rct::RCTTypeFullBulletproof && x.type != rct::RCTTypeSimpleBulletproof && x.type != rct::RCTTypeCLSAG && x.type != rct::RCTTypeBulletproofPlus && x.type != rct::RCTTypeBulletproofPlus_FullCommit)
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type"); 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.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 // a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
@@ -369,7 +369,7 @@ namespace boost
a & x.type; a & x.type;
if (x.type == rct::RCTTypeNull) if (x.type == rct::RCTTypeNull)
return; return;
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2 && x.type != rct::RCTTypeCLSAG && x.type != rct::RCTTypeBulletproofPlus) if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2 && x.type != rct::RCTTypeFullBulletproof && x.type != rct::RCTTypeSimpleBulletproof && x.type != rct::RCTTypeCLSAG && x.type != rct::RCTTypeBulletproofPlus && x.type != rct::RCTTypeBulletproofPlus_FullCommit)
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type"); 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.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 // a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
@@ -389,7 +389,7 @@ namespace boost
a & x.p.MGs; a & x.p.MGs;
if (ver >= 1u) if (ver >= 1u)
a & x.p.CLSAGs; a & x.p.CLSAGs;
if (x.type == rct::RCTTypeBulletproof || x.type == rct::RCTTypeBulletproof2 || x.type == rct::RCTTypeCLSAG || x.type == rct::RCTTypeBulletproofPlus) if (x.type == rct::RCTTypeBulletproof || x.type == rct::RCTTypeBulletproof2 || x.type == rct::RCTTypeSimpleBulletproof || x.type == rct::RCTTypeCLSAG || x.type == rct::RCTTypeBulletproofPlus || x.type == rct::RCTTypeBulletproofPlus_FullCommit)
a & x.p.pseudoOuts; a & x.p.pseudoOuts;
} }

View File

@@ -106,7 +106,7 @@ namespace cryptonote
uint64_t get_transaction_weight_clawback(const transaction &tx, size_t n_padded_outputs) uint64_t get_transaction_weight_clawback(const transaction &tx, size_t n_padded_outputs)
{ {
const rct::rctSig &rv = tx.rct_signatures; const rct::rctSig &rv = tx.rct_signatures;
const bool plus = rv.type == rct::RCTTypeBulletproofPlus; const bool plus = rv.type == rct::RCTTypeBulletproofPlus || rv.type == rct::RCTTypeBulletproofPlus_FullCommit;
const uint64_t bp_base = (32 * ((plus ? 6 : 9) + 7 * 2)) / 2; // notional size of a 2 output proof, normalized to 1 proof (ie, divided by 2) const uint64_t bp_base = (32 * ((plus ? 6 : 9) + 7 * 2)) / 2; // notional size of a 2 output proof, normalized to 1 proof (ie, divided by 2)
const size_t n_outputs = tx.vout.size(); const size_t n_outputs = tx.vout.size();
if (n_padded_outputs <= 2) if (n_padded_outputs <= 2)
@@ -167,7 +167,7 @@ namespace cryptonote
if (!base_only) if (!base_only)
{ {
const bool bulletproof = rct::is_rct_bulletproof(rv.type); const bool bulletproof = rct::is_rct_bulletproof(rv.type);
const bool bulletproof_plus = rct::is_rct_bulletproof_plus(rv.type); const bool bulletproof_plus = rct::is_rct_bulletproof_plus_any(rv.type);
if (bulletproof_plus) if (bulletproof_plus)
{ {
if (rv.p.bulletproofs_plus.size() != 1) if (rv.p.bulletproofs_plus.size() != 1)
@@ -188,11 +188,13 @@ namespace cryptonote
} }
const size_t n_amounts = tx.vout.size(); const size_t n_amounts = tx.vout.size();
CHECK_AND_ASSERT_MES(n_amounts == rv.outPk.size(), false, "Internal error filling out V"); CHECK_AND_ASSERT_MES(n_amounts == rv.outPk.size(), false, "Internal error filling out V");
rv.p.bulletproofs_plus[0].V.resize(n_amounts); rv.p.bulletproofs_plus[0].V.resize(n_amounts);
for (size_t i = 0; i < n_amounts; ++i) const bool bulletproof_plus_legacy = rct::is_rct_bp_plus_legacy(rv.type);
rv.p.bulletproofs_plus[0].V[i] = rct::scalarmultKey(rv.outPk[i].mask, rct::INV_EIGHT); for (size_t i = 0; i < n_amounts; ++i) {
rv.p.bulletproofs_plus[0].V[i] = bulletproof_plus_legacy ? rv.outPk[i].mask : rct::scalarmultKey(rv.outPk[i].mask, rct::INV_EIGHT);
}
} }
else if (bulletproof) if (rct::is_rct_new_bulletproof(rv.type))
{ {
if (rv.p.bulletproofs.size() != 1) if (rv.p.bulletproofs.size() != 1)
{ {
@@ -205,7 +207,7 @@ namespace cryptonote
return false; return false;
} }
const size_t max_outputs = 1 << (rv.p.bulletproofs[0].L.size() - 6); 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)); LOG_PRINT_L1("Failed to parse transaction from blob, bad bulletproofs max outputs in tx " << get_transaction_hash(tx));
return false; return false;
@@ -216,6 +218,24 @@ namespace cryptonote
for (size_t i = 0; i < n_amounts; ++i) for (size_t i = 0; i < n_amounts; ++i)
rv.p.bulletproofs[0].V[i] = rct::scalarmultKey(rv.outPk[i].mask, rct::INV_EIGHT); 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)
{
CHECK_AND_ASSERT_MES(rv.p.bulletproofs[n].L.size() >= 6, false, "Bad bulletproofs L size");
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);
for (size_t i = 0; i < n_amounts; ++i)
rv.p.bulletproofs[n].V[i] = rv.outPk[idx++].mask;
}
}
} }
} }
return true; return true;
@@ -449,9 +469,14 @@ namespace cryptonote
return blob_size; return blob_size;
const rct::rctSig &rv = tx.rct_signatures; const rct::rctSig &rv = tx.rct_signatures;
const bool bulletproof = rct::is_rct_bulletproof(rv.type); const bool bulletproof = rct::is_rct_bulletproof(rv.type);
const bool bulletproof_plus = rct::is_rct_bulletproof_plus(rv.type); const bool bulletproof_plus = rct::is_rct_bulletproof_plus_any(rv.type);
if (!bulletproof && !bulletproof_plus) if (!bulletproof && !bulletproof_plus)
return blob_size; return blob_size;
const size_t n_outputs = tx.vout.size();
if (n_outputs <= 2)
return blob_size;
if (rct::is_rct_old_bulletproof(rv.type))
return blob_size;
const size_t n_padded_outputs = bulletproof_plus ? rct::n_bulletproof_plus_max_amounts(rv.p.bulletproofs_plus) : rct::n_bulletproof_max_amounts(rv.p.bulletproofs); const size_t n_padded_outputs = bulletproof_plus ? rct::n_bulletproof_plus_max_amounts(rv.p.bulletproofs_plus) : rct::n_bulletproof_max_amounts(rv.p.bulletproofs);
uint64_t bp_clawback = get_transaction_weight_clawback(tx, n_padded_outputs); uint64_t bp_clawback = get_transaction_weight_clawback(tx, n_padded_outputs);
CHECK_AND_ASSERT_THROW_MES_L1(bp_clawback <= std::numeric_limits<uint64_t>::max() - blob_size, "Weight overflow"); CHECK_AND_ASSERT_THROW_MES_L1(bp_clawback <= std::numeric_limits<uint64_t>::max() - blob_size, "Weight overflow");
@@ -462,7 +487,7 @@ namespace cryptonote
{ {
CHECK_AND_ASSERT_MES(tx.pruned, std::numeric_limits<uint64_t>::max(), "get_pruned_transaction_weight does not support non pruned txes"); CHECK_AND_ASSERT_MES(tx.pruned, std::numeric_limits<uint64_t>::max(), "get_pruned_transaction_weight does not support non pruned txes");
CHECK_AND_ASSERT_MES(tx.version >= 2, std::numeric_limits<uint64_t>::max(), "get_pruned_transaction_weight does not support v1 txes"); CHECK_AND_ASSERT_MES(tx.version >= 2, std::numeric_limits<uint64_t>::max(), "get_pruned_transaction_weight does not support v1 txes");
CHECK_AND_ASSERT_MES(tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus, CHECK_AND_ASSERT_MES(tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus_FullCommit,
std::numeric_limits<uint64_t>::max(), "Unsupported rct_signatures type in get_pruned_transaction_weight"); std::numeric_limits<uint64_t>::max(), "Unsupported rct_signatures type in get_pruned_transaction_weight");
CHECK_AND_ASSERT_MES(!tx.vin.empty(), std::numeric_limits<uint64_t>::max(), "empty vin"); CHECK_AND_ASSERT_MES(!tx.vin.empty(), std::numeric_limits<uint64_t>::max(), "empty vin");
CHECK_AND_ASSERT_MES(tx.vin[0].type() == typeid(cryptonote::txin_to_key), std::numeric_limits<uint64_t>::max(), "empty vin"); CHECK_AND_ASSERT_MES(tx.vin[0].type() == typeid(cryptonote::txin_to_key), std::numeric_limits<uint64_t>::max(), "empty vin");
@@ -481,7 +506,7 @@ namespace cryptonote
while ((n_padded_outputs = (1u << nrl)) < tx.vout.size()) while ((n_padded_outputs = (1u << nrl)) < tx.vout.size())
++nrl; ++nrl;
nrl += 6; nrl += 6;
extra = 32 * ((rct::is_rct_bulletproof_plus(tx.rct_signatures.type) ? 6 : 9) + 2 * nrl) + 2; extra = 32 * ((rct::is_rct_bulletproof_plus_any(tx.rct_signatures.type) ? 6 : 9) + 2 * nrl) + 2;
weight += extra; weight += extra;
// calculate deterministic CLSAG/MLSAG data size // calculate deterministic CLSAG/MLSAG data size

View File

@@ -203,6 +203,7 @@
#define HF_VERSION_BLOCK_HEADER_MINER_SIG 18 #define HF_VERSION_BLOCK_HEADER_MINER_SIG 18
#define HF_VERSION_VIEW_TAGS 20 #define HF_VERSION_VIEW_TAGS 20
#define HF_VERSION_2021_SCALING 20 #define HF_VERSION_2021_SCALING 20
#define HF_VERSION_BP_PLUS_FULL_COMMIT 21
#define PER_KB_FEE_QUANTIZATION_DECIMALS 8 #define PER_KB_FEE_QUANTIZATION_DECIMALS 8
#define CRYPTONOTE_SCALING_2021_FEE_ROUNDING_PLACES 2 #define CRYPTONOTE_SCALING_2021_FEE_ROUNDING_PLACES 2

View File

@@ -3133,7 +3133,7 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
} }
} }
// from v10, allow bulletproofs v2 // from v13, allow bulletproofs v2
if (hf_version < HF_VERSION_SMALLER_BP) { if (hf_version < HF_VERSION_SMALLER_BP) {
if (tx.version >= 2) { if (tx.version >= 2) {
if (tx.rct_signatures.type == rct::RCTTypeBulletproof2) if (tx.rct_signatures.type == rct::RCTTypeBulletproof2)
@@ -3145,7 +3145,7 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
} }
} }
// from v11, allow only bulletproofs v2 // from v14, allow only bulletproofs v2
if (hf_version > HF_VERSION_SMALLER_BP) { if (hf_version > HF_VERSION_SMALLER_BP) {
if (tx.version >= 2) { if (tx.version >= 2) {
if (tx.rct_signatures.type == rct::RCTTypeBulletproof) if (tx.rct_signatures.type == rct::RCTTypeBulletproof)
@@ -3157,7 +3157,7 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
} }
} }
// from v13, allow CLSAGs // from v16, allow CLSAGs
if (hf_version < HF_VERSION_CLSAG) { if (hf_version < HF_VERSION_CLSAG) {
if (tx.version >= 2) { if (tx.version >= 2) {
if (tx.rct_signatures.type == rct::RCTTypeCLSAG) if (tx.rct_signatures.type == rct::RCTTypeCLSAG)
@@ -3169,7 +3169,7 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
} }
} }
// from v14, allow only CLSAGs // from v17, allow only CLSAGs
if (hf_version > HF_VERSION_CLSAG) { if (hf_version > HF_VERSION_CLSAG) {
if (tx.version >= 2) { if (tx.version >= 2) {
if (tx.rct_signatures.type <= rct::RCTTypeBulletproof2) if (tx.rct_signatures.type <= rct::RCTTypeBulletproof2)
@@ -3181,11 +3181,25 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
} }
} }
// from v15, allow bulletproofs plus
// 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;
}
}
}
// from v18, allow bulletproofs plus
if (hf_version < HF_VERSION_BULLETPROOF_PLUS) { if (hf_version < HF_VERSION_BULLETPROOF_PLUS) {
if (tx.version >= 2) { if (tx.version >= 2) {
const bool bulletproof_plus = rct::is_rct_bulletproof_plus(tx.rct_signatures.type); const bool bulletproof_plus_legacy = rct::is_rct_bp_plus_legacy(tx.rct_signatures.type);
if (bulletproof_plus || !tx.rct_signatures.p.bulletproofs_plus.empty()) if (bulletproof_plus_legacy || !tx.rct_signatures.p.bulletproofs_plus.empty())
{ {
MERROR_VER("Bulletproofs plus are not allowed before v" << std::to_string(HF_VERSION_BULLETPROOF_PLUS)); MERROR_VER("Bulletproofs plus are not allowed before v" << std::to_string(HF_VERSION_BULLETPROOF_PLUS));
tvc.m_invalid_output = true; tvc.m_invalid_output = true;
@@ -3194,7 +3208,7 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
} }
} }
// from v16, forbid bulletproofs // from v19, forbid bulletproofs
if (hf_version > HF_VERSION_BULLETPROOF_PLUS) { if (hf_version > HF_VERSION_BULLETPROOF_PLUS) {
if (tx.version >= 2) { if (tx.version >= 2) {
const bool bulletproof = rct::is_rct_bulletproof(tx.rct_signatures.type); const bool bulletproof = rct::is_rct_bulletproof(tx.rct_signatures.type);
@@ -3207,13 +3221,33 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
} }
} }
// from v15, require view tags on outputs // from v20, require view tags on outputs
if (!check_output_types(tx, hf_version)) if (!check_output_types(tx, hf_version))
{ {
tvc.m_invalid_output = true; tvc.m_invalid_output = true;
return false; return false;
} }
// from v21, allow bulletproofs plus full commit
if (hf_version < HF_VERSION_BP_PLUS_FULL_COMMIT) {
if (tx.version >= 2) {
const bool bulletproof_plus_full_commit = rct::is_rct_bp_plus_full(tx.rct_signatures.type);
if (bulletproof_plus_full_commit)
{
MERROR_VER("Bulletproofs plus full commit are not allowed before v" << std::to_string(HF_VERSION_BP_PLUS_FULL_COMMIT));
tvc.m_invalid_output = true;
return false;
}
}
}
// from v22, forbid bulletproof plus legacy
if (hf_version > HF_VERSION_BP_PLUS_FULL_COMMIT && rct::is_rct_bp_plus_legacy(tx.rct_signatures.type)) {
MERROR_VER("Bulletproof Plus legacy range proofs are not allowed after v" << (HF_VERSION_BP_PLUS_FULL_COMMIT + 1));
tvc.m_invalid_output = true;
return false;
}
return true; return true;
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
@@ -3239,7 +3273,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
rv.message = rct::hash2rct(tx_prefix_hash); rv.message = rct::hash2rct(tx_prefix_hash);
// mixRing - full and simple store it in opposite ways // 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"); CHECK_AND_ASSERT_MES(!pubkeys.empty() && !pubkeys[0].empty(), false, "empty pubkeys");
rv.mixRing.resize(pubkeys[0].size()); rv.mixRing.resize(pubkeys[0].size());
@@ -3254,7 +3288,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
} }
} }
} }
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeBulletproof2 || rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus) else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeBulletproof2 || rv.type == rct::RCTTypeSimpleBulletproof || rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus || rv.type == rct::RCTTypeBulletproofPlus_FullCommit)
{ {
CHECK_AND_ASSERT_MES(!pubkeys.empty() && !pubkeys[0].empty(), false, "empty pubkeys"); CHECK_AND_ASSERT_MES(!pubkeys.empty() && !pubkeys[0].empty(), false, "empty pubkeys");
rv.mixRing.resize(pubkeys.size()); rv.mixRing.resize(pubkeys.size());
@@ -3273,7 +3307,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
} }
// II // II
if (rv.type == rct::RCTTypeFull) if (rv.type == rct::RCTTypeFull || rv.type == rct::RCTTypeFullBulletproof)
{ {
if (!tx.pruned) if (!tx.pruned)
{ {
@@ -3283,7 +3317,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
rv.p.MGs[0].II[n] = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image); 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 || rv.type == rct::RCTTypeBulletproof2) else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeBulletproof2 || rv.type == rct::RCTTypeSimpleBulletproof)
{ {
if (!tx.pruned) if (!tx.pruned)
{ {
@@ -3295,7 +3329,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
} }
} }
} }
else if (rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus) else if (rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus || rv.type == rct::RCTTypeBulletproofPlus_FullCommit)
{ {
if (!tx.pruned) if (!tx.pruned)
{ {
@@ -3548,11 +3582,9 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
} }
// Warn that new RCT types are present, and thus the cache is not being used effectively // Warn that new RCT types are present, and thus the cache is not being used effectively
static constexpr const std::uint8_t RCT_CACHE_TYPE = rct::RCTTypeBulletproofPlus; const std::uint8_t rct_cache_type = (hf_version >= HF_VERSION_BP_PLUS_FULL_COMMIT) ? static_cast<std::uint8_t>(rct::RCTTypeBulletproofPlus_FullCommit) : static_cast<std::uint8_t>(rct::RCTTypeBulletproofPlus);
if (tx.rct_signatures.type > RCT_CACHE_TYPE) if (static_cast<std::uint8_t>(tx.rct_signatures.type) > rct_cache_type)
{ MWARNING("RCT cache is not caching new verification results. Please update rct_cache_type.");
MWARNING("RCT cache is not caching new verification results. Please update RCT_CACHE_TYPE!");
}
if (tx.version == 1) if (tx.version == 1)
{ {
@@ -3587,12 +3619,14 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
return false; return false;
} }
case rct::RCTTypeSimple: case rct::RCTTypeSimple:
case rct::RCTTypeSimpleBulletproof:
case rct::RCTTypeBulletproof: case rct::RCTTypeBulletproof:
case rct::RCTTypeBulletproof2: case rct::RCTTypeBulletproof2:
case rct::RCTTypeCLSAG: case rct::RCTTypeCLSAG:
case rct::RCTTypeBulletproofPlus: case rct::RCTTypeBulletproofPlus:
case rct::RCTTypeBulletproofPlus_FullCommit:
{ {
if (!ver_rct_non_semantics_simple_cached(tx, pubkeys, m_rct_ver_cache, RCT_CACHE_TYPE)) if (!ver_rct_non_semantics_simple_cached(tx, pubkeys, m_rct_ver_cache, rct_cache_type))
{ {
MERROR_VER("Failed to check ringct signatures!"); MERROR_VER("Failed to check ringct signatures!");
return false; return false;
@@ -3600,6 +3634,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
break; break;
} }
case rct::RCTTypeFull: case rct::RCTTypeFull:
case rct::RCTTypeFullBulletproof:
{ {
if (!expand_transaction_2(tx, tx_prefix_hash, pubkeys)) if (!expand_transaction_2(tx, tx_prefix_hash, pubkeys))
{ {

View File

@@ -603,7 +603,9 @@ namespace cryptonote
crypto::hash tx_prefix_hash; crypto::hash tx_prefix_hash;
get_transaction_prefix_hash(tx, tx_prefix_hash, hwdev); get_transaction_prefix_hash(tx, tx_prefix_hash, hwdev);
rct::ctkeyV outSk; rct::ctkeyV outSk;
if (use_simple_rct) if (rct_config.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, index, outSk, rct_config, hwdev);
else if (use_simple_rct && rct_config.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, index, outSk, rct_config, hwdev); tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, index, outSk, rct_config, hwdev);
else else
tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, sources[0].real_output, outSk, rct_config, hwdev); // same index assumption tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, sources[0].real_output, outSk, rct_config, hwdev); // same index assumption

View File

@@ -226,7 +226,7 @@ bool ver_rct_non_semantics_simple_cached
// mixring. Future versions of the protocol may differ in this regard, but if this assumptions // mixring. Future versions of the protocol may differ in this regard, but if this assumptions
// holds true in the future, enable the verification hash by modifying the `untested_tx` // holds true in the future, enable the verification hash by modifying the `untested_tx`
// condition below. // condition below.
const bool untested_tx = tx.version > 2 || tx.rct_signatures.type > rct::RCTTypeBulletproofPlus; const bool untested_tx = (tx.version > 2) || (static_cast<std::uint8_t>(tx.rct_signatures.type) > rct_type_to_cache);
VER_ASSERT(!untested_tx, "Unknown TX type. Make sure RCT cache works correctly with this type and then enable it in the code here."); VER_ASSERT(!untested_tx, "Unknown TX type. Make sure RCT cache works correctly with this type and then enable it in the code here.");
// Don't cache older (or newer) rctSig types // Don't cache older (or newer) rctSig types
@@ -302,6 +302,7 @@ bool ver_mixed_rct_semantics(std::vector<const rct::rctSig*> rvv)
is_batchable_rv = true; is_batchable_rv = true;
break; break;
case rct::RCTTypeBulletproofPlus: case rct::RCTTypeBulletproofPlus:
case rct::RCTTypeBulletproofPlus_FullCommit:
if (!is_canonical_bulletproof_plus_layout(rv.p.bulletproofs_plus)) if (!is_canonical_bulletproof_plus_layout(rv.p.bulletproofs_plus))
{ {
MERROR("Bulletproof_plus does not have canonical form"); MERROR("Bulletproof_plus does not have canonical form");

View File

@@ -2193,7 +2193,7 @@ skip:
} }
const uint64_t first_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1; const uint64_t first_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1;
static const uint64_t bp_fork_height = m_core.get_earliest_ideal_height_for_version(8); static const uint64_t bp_fork_height = m_core.get_earliest_ideal_height_for_version(HF_VERSION_SMALLER_BP +1);
bool sync_pruned_blocks = m_sync_pruned_blocks && first_block_height >= bp_fork_height && m_core.get_blockchain_pruning_seed(); bool sync_pruned_blocks = m_sync_pruned_blocks && first_block_height >= bp_fork_height && m_core.get_blockchain_pruning_seed();
span = m_block_queue.reserve_span(first_block_height, context.m_last_response_height, count_limit, context.m_connection_id, context.m_remote_address, sync_pruned_blocks, m_core.get_blockchain_pruning_seed(), context.m_pruning_seed, context.m_remote_blockchain_height, context.m_needed_objects); span = m_block_queue.reserve_span(first_block_height, context.m_last_response_height, count_limit, context.m_connection_id, context.m_remote_address, sync_pruned_blocks, m_core.get_blockchain_pruning_seed(), context.m_pruning_seed, context.m_remote_blockchain_height, context.m_needed_objects);
MDEBUG(context << " span from " << first_block_height << ": " << span.first << "/" << span.second); MDEBUG(context << " span from " << first_block_height << ": " << span.first << "/" << span.second);

View File

@@ -1929,7 +1929,7 @@ namespace hw {
// ====== Aout, Bout, AKout, C, v, k ====== // ====== Aout, Bout, AKout, C, v, k ======
kv_offset = data_offset; kv_offset = data_offset;
if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus) { if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus || type==rct::RCTTypeBulletproofPlus_FullCommit) {
C_offset = kv_offset+ (8)*outputs_size; C_offset = kv_offset+ (8)*outputs_size;
} else { } else {
C_offset = kv_offset+ (32+32)*outputs_size; C_offset = kv_offset+ (32+32)*outputs_size;
@@ -1946,7 +1946,7 @@ namespace hw {
offset = set_command_header(INS_VALIDATE, 0x02, i+1); offset = set_command_header(INS_VALIDATE, 0x02, i+1);
//options //options
this->buffer_send[offset] = (i==outputs_size-1)? 0x00:0x80 ; this->buffer_send[offset] = (i==outputs_size-1)? 0x00:0x80 ;
this->buffer_send[offset] |= (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus)?0x02:0x00; this->buffer_send[offset] |= (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus || type==rct::RCTTypeBulletproofPlus_FullCommit)?0x02:0x00;
offset += 1; offset += 1;
//is_subaddress //is_subaddress
this->buffer_send[offset] = outKeys.is_subaddress; this->buffer_send[offset] = outKeys.is_subaddress;
@@ -1967,7 +1967,7 @@ namespace hw {
memmove(this->buffer_send+offset, data+C_offset,32); memmove(this->buffer_send+offset, data+C_offset,32);
offset += 32; offset += 32;
C_offset += 32; C_offset += 32;
if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus) { if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus || type==rct::RCTTypeBulletproofPlus_FullCommit) {
//k //k
memset(this->buffer_send+offset, 0, 32); memset(this->buffer_send+offset, 0, 32);
offset += 32; offset += 32;

View File

@@ -312,12 +312,12 @@ namespace tx {
bool is_bulletproof() const { bool is_bulletproof() const {
auto tp = get_rv_type(); auto tp = get_rv_type();
return rct::is_rct_bulletproof(tp) || rct::is_rct_bulletproof_plus(tp); return rct::is_rct_bulletproof(tp) || rct::is_rct_bulletproof_plus_any(tp);
} }
bool is_bulletproof_plus() const { bool is_bulletproof_plus() const {
auto tp = get_rv_type(); auto tp = get_rv_type();
return rct::is_rct_bulletproof_plus(tp); return rct::is_rct_bulletproof_plus_any(tp);
} }
bool is_clsag() const { bool is_clsag() const {

View File

@@ -546,6 +546,7 @@ static void make_new_range_proofs(const int bp_version,
//---------------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------------
static bool try_reconstruct_range_proofs(const int bp_version, static bool try_reconstruct_range_proofs(const int bp_version,
const uint8_t sig_type,
const rct::rctSigPrunable& original_sigs, const rct::rctSigPrunable& original_sigs,
const std::size_t num_destinations, const std::size_t num_destinations,
const rct::ctkeyV& output_public_keys, const rct::ctkeyV& output_public_keys,
@@ -559,8 +560,13 @@ static bool try_reconstruct_range_proofs(const int bp_version,
new_range_proofs = original_range_proofs; new_range_proofs = original_range_proofs;
new_range_proofs[0].V.resize(num_destinations); new_range_proofs[0].V.resize(num_destinations);
for (std::size_t i = 0; i < num_destinations; ++i) const bool is_full = (bp_version == 4) && (sig_type == rct::RCTTypeBulletproofPlus_FullCommit);
new_range_proofs[0].V[i] = rct::scalarmultKey(output_public_keys[i].mask, rct::INV_EIGHT); for (std::size_t i = 0; i < num_destinations; ++i) {
if (bp_version == 4)
new_range_proofs[0].V[i] = is_full ? rct::scalarmultKey(output_public_keys[i].mask, rct::INV_EIGHT) : output_public_keys[i].mask;
else
new_range_proofs[0].V[i] = rct::scalarmultKey(output_public_keys[i].mask, rct::INV_EIGHT);
}
return true; return true;
}; };
@@ -612,7 +618,7 @@ static bool set_tx_rct_signatures(
if (rct_config.bp_version == 3) if (rct_config.bp_version == 3)
rv.type = rct::RCTTypeCLSAG; rv.type = rct::RCTTypeCLSAG;
else if (rct_config.bp_version == 4) else if (rct_config.bp_version == 4)
rv.type = rct::RCTTypeBulletproofPlus; rv.type = (unsigned_tx.rct_signatures.type == rct::RCTTypeBulletproofPlus_FullCommit) ? rct::RCTTypeBulletproofPlus_FullCommit : rct::RCTTypeBulletproofPlus;
else else
return false; return false;
rv.txnFee = fee; rv.txnFee = fee;
@@ -643,6 +649,7 @@ static bool set_tx_rct_signatures(
} }
else { else {
if (not try_reconstruct_range_proofs(rct_config.bp_version, if (not try_reconstruct_range_proofs(rct_config.bp_version,
rv.type,
unsigned_tx.rct_signatures.p, unsigned_tx.rct_signatures.p,
num_destinations, num_destinations,
rv.outPk, rv.outPk,

View File

@@ -32,6 +32,7 @@ set(ringct_basic_sources
rctCryptoOps.c rctCryptoOps.c
multiexp.cc multiexp.cc
bulletproofs.cc bulletproofs.cc
legacy_bp/bulletproofs_old.cc
bulletproofs_plus.cc) bulletproofs_plus.cc)
monero_find_all_headers(ringct_basic_private_headers "${CMAKE_CURRENT_SOURCE_DIR}") monero_find_all_headers(ringct_basic_private_headers "${CMAKE_CURRENT_SOURCE_DIR}")
@@ -51,12 +52,14 @@ target_link_libraries(ringct_basic
set(ringct_sources set(ringct_sources
rctSigs.cpp rctSigs.cpp
legacy_bp/rctSigs_old.cpp
) )
set(ringct_headers) set(ringct_headers)
set(ringct_private_headers set(ringct_private_headers
rctSigs.h rctSigs.h
legacy_bp/rctSigs_old.h
) )
monero_private_headers(ringct monero_private_headers(ringct

View File

@@ -42,9 +42,16 @@ 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);
Bulletproof bulletproof_PROVE(const rct::keyV &v, const rct::keyV &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(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 Bulletproof &proof);
bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs); bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs);
bool bulletproof_VERIFY(const std::vector<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);
} }

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,137 @@
#include <vector>
#include "misc_log_ex.h"
#include "misc_language.h"
#include "common/perf_timer.h"
#include "common/threadpool.h"
#include "common/util.h"
#include "ringct/rctSigs.h"
#include "ringct/bulletproofs.h"
#include "ringct/bulletproofs_plus.h"
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "cryptonote_config.h"
#include "rctSigs_old.h"
using std::vector;
namespace rct {
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_old(const Bulletproof &proof)
{
try { return bulletproof_VERIFY_old(proof); }
catch (...) { return false; }
}
bool verBulletproof_old(const std::vector<const Bulletproof*> &proofs)
{
try { return bulletproof_VERIFY_old(proofs); }
catch (...) { return false; }
}
xmr_amount populateFromBlockchainSimple(ctkeyV & mixRing, const ctkey & inPk, int mixin);
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<unsigned int> & index, ctkeyV &outSk, const RCTConfig &rct_config, hw::device &hwdev) {
const bool bulletproof = rct_config.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");
}
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], rv.type == RCTTypeSimpleBulletproof);
}
rv.txnFee = 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);
for (i = 0 ; i < inamounts.size(); i++) {
rv.p.MGs[i] = proveRctMGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], 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, xmr_amount txnFee, unsigned int mixin, const RCTConfig &rct_config, 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, index, outSk, rct_config, hwdev);
}
} // namespace rct

View File

@@ -0,0 +1,20 @@
#pragma once
#include <vector>
#include "ringct/rctSigs.h"
#include "ringct/bulletproofs.h"
namespace hw { class device; }
namespace rct {
Bulletproof proveRangeBulletproof_old(key &C, key &mask, uint64_t amount);
Bulletproof proveRangeBulletproof_old(keyV &C, keyV &masks, const std::vector<uint64_t> &amounts);
bool verBulletproof_old(const Bulletproof &proof);
bool verBulletproof_old(const std::vector<const Bulletproof*> &proofs);
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<unsigned int> & index, ctkeyV &outSk, const RCTConfig &rct_config, 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, xmr_amount txnFee, unsigned int mixin, const RCTConfig &rct_config, hw::device &hwdev);
} // namespace rct

View File

@@ -38,6 +38,7 @@
#include "bulletproofs_plus.h" #include "bulletproofs_plus.h"
#include "cryptonote_basic/cryptonote_format_utils.h" #include "cryptonote_basic/cryptonote_format_utils.h"
#include "cryptonote_config.h" #include "cryptonote_config.h"
#include "legacy_bp/rctSigs_old.h"
using namespace crypto; using namespace crypto;
using namespace std; using namespace std;
@@ -616,7 +617,7 @@ namespace rct {
hashes.push_back(hash2rct(h)); hashes.push_back(hash2rct(h));
keyV kv; keyV kv;
if (rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG) if (rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeSimpleBulletproof || rv.type == RCTTypeFullBulletproof || rv.type == RCTTypeCLSAG)
{ {
kv.reserve((6*2+9) * rv.p.bulletproofs.size()); kv.reserve((6*2+9) * rv.p.bulletproofs.size());
for (const auto &p: rv.p.bulletproofs) for (const auto &p: rv.p.bulletproofs)
@@ -638,7 +639,7 @@ namespace rct {
kv.push_back(p.t); kv.push_back(p.t);
} }
} }
else if (rv.type == RCTTypeBulletproofPlus) else if (rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeBulletproofPlus_FullCommit)
{ {
kv.reserve((6*2+6) * rv.p.bulletproofs_plus.size()); kv.reserve((6*2+6) * rv.p.bulletproofs_plus.size());
for (const auto &p: rv.p.bulletproofs_plus) for (const auto &p: rv.p.bulletproofs_plus)
@@ -1044,6 +1045,7 @@ namespace rct {
// 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, const RCTConfig &rct_config, 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, unsigned int index, ctkeyV &outSk, const RCTConfig &rct_config, hw::device &hwdev) {
const bool bulletproof = rct_config.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(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");
@@ -1053,10 +1055,11 @@ namespace rct {
CHECK_AND_ASSERT_THROW_MES(inSk.size() < 2, "genRct is not suitable for 2+ rings"); CHECK_AND_ASSERT_THROW_MES(inSk.size() < 2, "genRct is not suitable for 2+ rings");
rctSig rv; rctSig rv;
rv.type = RCTTypeFull; rv.type = bulletproof ? RCTTypeFullBulletproof : RCTTypeFull;
rv.message = message; rv.message = message;
rv.outPk.resize(destinations.size()); rv.outPk.resize(destinations.size());
rv.p.rangeSigs.resize(destinations.size()); if (!bulletproof)
rv.p.rangeSigs.resize(destinations.size());
rv.ecdhInfo.resize(destinations.size()); rv.ecdhInfo.resize(destinations.size());
size_t i = 0; size_t i = 0;
@@ -1066,14 +1069,49 @@ 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
rv.p.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, amounts[i]); if (!bulletproof)
{
rv.p.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, amounts[i]);
#ifdef DBG #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 #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 (rct_config.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 //mask amount and mask
rv.ecdhInfo[i].mask = copy(outSk[i].mask); rv.ecdhInfo[i].mask = copy(outSk[i].mask);
rv.ecdhInfo[i].amount = d2h(amounts[i]); rv.ecdhInfo[i].amount = d2h(amounts[i]);
hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus); hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeBulletproofPlus_FullCommit);
} }
//set txn fee //set txn fee
@@ -1121,7 +1159,7 @@ namespace rct {
{ {
case 0: case 0:
case 4: case 4:
rv.type = RCTTypeBulletproofPlus; rv.type = (rv.type == rct::RCTTypeBulletproofPlus_FullCommit) ? rct::RCTTypeBulletproofPlus_FullCommit : rct::RCTTypeBulletproofPlus;
break; break;
case 3: case 3:
rv.type = RCTTypeCLSAG; rv.type = RCTTypeCLSAG;
@@ -1165,7 +1203,9 @@ namespace rct {
rv.p.bulletproofs_plus.clear(); rv.p.bulletproofs_plus.clear();
if (bulletproof_or_plus) if (bulletproof_or_plus)
{ {
const bool plus = is_rct_bulletproof_plus(rv.type); const bool bp_plus_full = is_rct_bp_plus_full(rv.type);
const bool bulletproof_plus = is_rct_bulletproof_plus_any(rv.type);
const bool bulletproof_plus_legacy = rct::is_rct_bp_plus_legacy(rv.type);
size_t n_amounts = outamounts.size(); size_t n_amounts = outamounts.size();
size_t amounts_proved = 0; size_t amounts_proved = 0;
if (rct_config.range_proof_type == RangeProofPaddedBulletproof) if (rct_config.range_proof_type == RangeProofPaddedBulletproof)
@@ -1174,7 +1214,7 @@ namespace rct {
if (hwdev.get_mode() == hw::device::TRANSACTION_CREATE_FAKE) if (hwdev.get_mode() == hw::device::TRANSACTION_CREATE_FAKE)
{ {
// use a fake bulletproof for speed // use a fake bulletproof for speed
if (plus) if (bulletproof_plus)
rv.p.bulletproofs_plus.push_back(make_dummy_bulletproof_plus(outamounts, C, masks)); rv.p.bulletproofs_plus.push_back(make_dummy_bulletproof_plus(outamounts, C, masks));
else else
rv.p.bulletproofs.push_back(make_dummy_bulletproof(outamounts, C, masks)); rv.p.bulletproofs.push_back(make_dummy_bulletproof(outamounts, C, masks));
@@ -1182,12 +1222,12 @@ namespace rct {
else else
{ {
const epee::span<const key> keys{&amount_keys[0], amount_keys.size()}; const epee::span<const key> keys{&amount_keys[0], amount_keys.size()};
if (plus) if (bulletproof_plus)
rv.p.bulletproofs_plus.push_back(proveRangeBulletproofPlus(C, masks, outamounts, keys, hwdev)); rv.p.bulletproofs_plus.push_back(proveRangeBulletproofPlus(C, masks, outamounts, keys, hwdev));
else else
rv.p.bulletproofs.push_back(proveRangeBulletproof(C, masks, outamounts, keys, hwdev)); rv.p.bulletproofs.push_back(proveRangeBulletproof(C, masks, outamounts, keys, hwdev));
#ifdef DBG #ifdef DBG
if (plus) if (bulletproof_plus)
CHECK_AND_ASSERT_THROW_MES(verBulletproofPlus(rv.p.bulletproofs_plus.back()), "verBulletproofPlus failed on newly created proof"); CHECK_AND_ASSERT_THROW_MES(verBulletproofPlus(rv.p.bulletproofs_plus.back()), "verBulletproofPlus failed on newly created proof");
else else
CHECK_AND_ASSERT_THROW_MES(verBulletproof(rv.p.bulletproofs.back()), "verBulletproof failed on newly created proof"); CHECK_AND_ASSERT_THROW_MES(verBulletproof(rv.p.bulletproofs.back()), "verBulletproof failed on newly created proof");
@@ -1195,15 +1235,20 @@ namespace rct {
} }
for (i = 0; i < outamounts.size(); ++i) for (i = 0; i < outamounts.size(); ++i)
{ {
if (bp_plus_full)
rv.outPk[i].mask = rct::scalarmult8(C[i]); rv.outPk[i].mask = rct::scalarmult8(C[i]);
outSk[i].mask = masks[i]; else if (bulletproof_plus_legacy)
rv.outPk[i].mask = C[i];
else
rv.outPk[i].mask = rct::scalarmult8(C[i]);
outSk[i].mask = masks[i];
} }
} }
else while (amounts_proved < n_amounts) else while (amounts_proved < n_amounts)
{ {
size_t batch_size = 1; size_t batch_size = 1;
if (rct_config.range_proof_type == RangeProofMultiOutputBulletproof) if (rct_config.range_proof_type == RangeProofMultiOutputBulletproof)
while (batch_size * 2 + amounts_proved <= n_amounts && batch_size * 2 <= (plus ? BULLETPROOF_PLUS_MAX_OUTPUTS : BULLETPROOF_MAX_OUTPUTS)) while (batch_size * 2 + amounts_proved <= n_amounts && batch_size * 2 <= (bulletproof_plus ? BULLETPROOF_PLUS_MAX_OUTPUTS : BULLETPROOF_MAX_OUTPUTS))
batch_size *= 2; batch_size *= 2;
rct::keyV C, masks; rct::keyV C, masks;
std::vector<uint64_t> batch_amounts(batch_size); std::vector<uint64_t> batch_amounts(batch_size);
@@ -1212,7 +1257,7 @@ namespace rct {
if (hwdev.get_mode() == hw::device::TRANSACTION_CREATE_FAKE) if (hwdev.get_mode() == hw::device::TRANSACTION_CREATE_FAKE)
{ {
// use a fake bulletproof for speed // use a fake bulletproof for speed
if (plus) if (bulletproof_plus)
rv.p.bulletproofs_plus.push_back(make_dummy_bulletproof_plus(batch_amounts, C, masks)); rv.p.bulletproofs_plus.push_back(make_dummy_bulletproof_plus(batch_amounts, C, masks));
else else
rv.p.bulletproofs.push_back(make_dummy_bulletproof(batch_amounts, C, masks)); rv.p.bulletproofs.push_back(make_dummy_bulletproof(batch_amounts, C, masks));
@@ -1220,12 +1265,12 @@ namespace rct {
else else
{ {
const epee::span<const key> keys{&amount_keys[amounts_proved], batch_size}; const epee::span<const key> keys{&amount_keys[amounts_proved], batch_size};
if (plus) if (bulletproof_plus)
rv.p.bulletproofs_plus.push_back(proveRangeBulletproofPlus(C, masks, batch_amounts, keys, hwdev)); rv.p.bulletproofs_plus.push_back(proveRangeBulletproofPlus(C, masks, batch_amounts, keys, hwdev));
else else
rv.p.bulletproofs.push_back(proveRangeBulletproof(C, masks, batch_amounts, keys, hwdev)); rv.p.bulletproofs.push_back(proveRangeBulletproof(C, masks, batch_amounts, keys, hwdev));
#ifdef DBG #ifdef DBG
if (plus) if (bulletproof_plus)
CHECK_AND_ASSERT_THROW_MES(verBulletproofPlus(rv.p.bulletproofs_plus.back()), "verBulletproofPlus failed on newly created proof"); CHECK_AND_ASSERT_THROW_MES(verBulletproofPlus(rv.p.bulletproofs_plus.back()), "verBulletproofPlus failed on newly created proof");
else else
CHECK_AND_ASSERT_THROW_MES(verBulletproof(rv.p.bulletproofs.back()), "verBulletproof failed on newly created proof"); CHECK_AND_ASSERT_THROW_MES(verBulletproof(rv.p.bulletproofs.back()), "verBulletproof failed on newly created proof");
@@ -1233,7 +1278,12 @@ namespace rct {
} }
for (i = 0; i < batch_size; ++i) for (i = 0; i < batch_size; ++i)
{ {
rv.outPk[i + amounts_proved].mask = rct::scalarmult8(C[i]); if (bp_plus_full)
rv.outPk[i + amounts_proved].mask = rct::scalarmult8(C[i]);
else if (bulletproof_plus_legacy)
rv.outPk[i + amounts_proved].mask = C[i];
else
rv.outPk[i + amounts_proved].mask = rct::scalarmult8(C[i]);
outSk[i + amounts_proved].mask = masks[i]; outSk[i + amounts_proved].mask = masks[i];
} }
amounts_proved += batch_size; amounts_proved += batch_size;
@@ -1248,7 +1298,7 @@ namespace rct {
//mask amount and mask //mask amount and mask
rv.ecdhInfo[i].mask = copy(outSk[i].mask); rv.ecdhInfo[i].mask = copy(outSk[i].mask);
rv.ecdhInfo[i].amount = d2h(outamounts[i]); rv.ecdhInfo[i].amount = d2h(outamounts[i]);
hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus); hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeBulletproofPlus_FullCommit);
} }
//set txn fee //set txn fee
@@ -1317,10 +1367,13 @@ 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
bool verRct(const rctSig & rv, bool semantics) { bool verRct(const rctSig & rv, bool semantics) {
PERF_TIMER(verRct); 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 (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"); 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.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");
} }
@@ -1335,10 +1388,23 @@ namespace rct {
if (semantics) { if (semantics) {
tools::threadpool& tpool = tools::threadpool::getInstanceForCompute(); tools::threadpool& tpool = tools::threadpool::getInstanceForCompute();
tools::threadpool::waiter waiter(tpool); tools::threadpool::waiter waiter(tpool);
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?"); DP("range proofs verified?");
for (size_t i = 0; i < rv.outPk.size(); i++) if (rct::is_rct_new_bulletproof(rv.type))
tpool.submit(&waiter, [&, i] { results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]); }); {
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]); });
}
if (!waiter.wait()) if (!waiter.wait())
return false; return false;
@@ -1394,10 +1460,10 @@ namespace rct {
{ {
CHECK_AND_ASSERT_MES(rvp, false, "rctSig pointer is NULL"); CHECK_AND_ASSERT_MES(rvp, false, "rctSig pointer is NULL");
const rctSig &rv = *rvp; const rctSig &rv = *rvp;
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus, CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeSimpleBulletproof || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeBulletproofPlus_FullCommit,
false, "verRctSemanticsSimple called on non simple rctSig"); false, "verRctSemanticsSimple called on non simple rctSig");
const bool bulletproof = is_rct_bulletproof(rv.type); const bool bulletproof = is_rct_bulletproof(rv.type);
const bool bulletproof_plus = is_rct_bulletproof_plus(rv.type); const bool bulletproof_plus = is_rct_bulletproof_plus_any(rv.type);
if (bulletproof || bulletproof_plus) if (bulletproof || bulletproof_plus)
{ {
if (bulletproof_plus) if (bulletproof_plus)
@@ -1434,12 +1500,16 @@ namespace rct {
const rctSig &rv = *rvp; const rctSig &rv = *rvp;
const bool bulletproof = is_rct_bulletproof(rv.type); const bool bulletproof = is_rct_bulletproof(rv.type);
const bool bulletproof_plus = is_rct_bulletproof_plus(rv.type); const bool bulletproof_plus = is_rct_bulletproof_plus_any(rv.type);
const bool bulletproof_plus_legacy = rct::is_rct_bp_plus_legacy(rv.type);
const keyV &pseudoOuts = bulletproof || bulletproof_plus ? rv.p.pseudoOuts : rv.pseudoOuts; const keyV &pseudoOuts = bulletproof || bulletproof_plus ? rv.p.pseudoOuts : rv.pseudoOuts;
rct::keyV masks(rv.outPk.size()); rct::keyV masks(rv.outPk.size());
for (size_t i = 0; i < rv.outPk.size(); i++) { for (size_t i = 0; i < rv.outPk.size(); i++) {
masks[i] = rv.outPk[i].mask; if (bulletproof_plus_legacy)
masks[i] = rct::scalarmult8(rv.outPk[i].mask);
else
masks[i] = rv.outPk[i].mask;
} }
key sumOutpks = addKeys(masks); key sumOutpks = addKeys(masks);
DP(sumOutpks); DP(sumOutpks);
@@ -1523,10 +1593,10 @@ namespace rct {
{ {
PERF_TIMER(verRctNonSemanticsSimple); PERF_TIMER(verRctNonSemanticsSimple);
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus, CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeSimpleBulletproof || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeBulletproofPlus_FullCommit,
false, "verRctNonSemanticsSimple called on non simple rctSig"); false, "verRctNonSemanticsSimple called on non simple rctSig");
const bool bulletproof = is_rct_bulletproof(rv.type); const bool bulletproof = is_rct_bulletproof(rv.type);
const bool bulletproof_plus = is_rct_bulletproof_plus(rv.type); const bool bulletproof_plus = is_rct_bulletproof_plus_any(rv.type);
// semantics check is early, and mixRing/MGs aren't resolved yet // semantics check is early, and mixRing/MGs aren't resolved yet
if (bulletproof || bulletproof_plus) if (bulletproof || bulletproof_plus)
CHECK_AND_ASSERT_MES(rv.p.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.p.pseudoOuts and mixRing"); CHECK_AND_ASSERT_MES(rv.p.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.p.pseudoOuts and mixRing");
@@ -1589,16 +1659,18 @@ namespace rct {
// 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
xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask, hw::device &hwdev) { 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(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"); CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo");
//mask amount and mask //mask amount and mask
ecdhTuple ecdh_info = rv.ecdhInfo[i]; ecdhTuple ecdh_info = rv.ecdhInfo[i];
hwdev.ecdhDecode(ecdh_info, sk, rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus); hwdev.ecdhDecode(ecdh_info, sk, rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeBulletproofPlus_FullCommit);
mask = ecdh_info.mask; mask = ecdh_info.mask;
key amount = ecdh_info.amount; key amount = ecdh_info.amount;
key C = rv.outPk[i].mask; key C = rv.outPk[i].mask;
if (is_rct_bp_plus_legacy(rv.type))
C = scalarmult8(C);
DP("C"); DP("C");
DP(C); DP(C);
key Ctmp; key Ctmp;
@@ -1619,17 +1691,19 @@ namespace rct {
} }
xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask, hw::device &hwdev) { 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 || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus, CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeSimpleBulletproof || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeBulletproofPlus_FullCommit,
false, "decodeRct called on non simple rctSig"); false, "decodeRct called on non simple rctSig");
CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index"); 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"); CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo");
//mask amount and mask //mask amount and mask
ecdhTuple ecdh_info = rv.ecdhInfo[i]; ecdhTuple ecdh_info = rv.ecdhInfo[i];
hwdev.ecdhDecode(ecdh_info, sk, rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus); hwdev.ecdhDecode(ecdh_info, sk, rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus || rv.type == RCTTypeBulletproofPlus_FullCommit);
mask = ecdh_info.mask; mask = ecdh_info.mask;
key amount = ecdh_info.amount; key amount = ecdh_info.amount;
key C = rv.outPk[i].mask; key C = rv.outPk[i].mask;
if (is_rct_bp_plus_legacy(rv.type))
C = scalarmult8(C);
DP("C"); DP("C");
DP(C); DP(C);
key Ctmp; key Ctmp;

View File

@@ -50,6 +50,7 @@ extern "C" {
#include "rctTypes.h" #include "rctTypes.h"
#include "rctOps.h" #include "rctOps.h"
#include "legacy_bp/rctSigs_old.h"
//Define this flag when debugging to get additional info on the console //Define this flag when debugging to get additional info on the console
#ifdef DBG #ifdef DBG

View File

@@ -193,10 +193,12 @@ namespace rct {
switch (type) switch (type)
{ {
case RCTTypeSimple: case RCTTypeSimple:
case RCTTypeSimpleBulletproof:
case RCTTypeBulletproof: case RCTTypeBulletproof:
case RCTTypeBulletproof2: case RCTTypeBulletproof2:
case RCTTypeCLSAG: case RCTTypeCLSAG:
case RCTTypeBulletproofPlus: case RCTTypeBulletproofPlus:
case RCTTypeBulletproofPlus_FullCommit:
return true; return true;
default: default:
return false; return false;
@@ -207,6 +209,8 @@ namespace rct {
{ {
switch (type) switch (type)
{ {
case RCTTypeSimpleBulletproof:
case RCTTypeFullBulletproof:
case RCTTypeBulletproof: case RCTTypeBulletproof:
case RCTTypeBulletproof2: case RCTTypeBulletproof2:
case RCTTypeCLSAG: case RCTTypeCLSAG:
@@ -216,17 +220,23 @@ namespace rct {
} }
} }
bool is_rct_bulletproof_plus(int type) bool is_rct_old_bulletproof(int type)
{ {
switch (type) switch (type)
{ {
case RCTTypeBulletproofPlus: case RCTTypeSimpleBulletproof:
case RCTTypeFullBulletproof:
return true; return true;
default: default:
return false; return false;
} }
} }
bool is_rct_new_bulletproof(int type)
{
return is_rct_bulletproof(type) && !is_rct_old_bulletproof(type);
}
bool is_rct_borromean(int type) bool is_rct_borromean(int type)
{ {
switch (type) switch (type)
@@ -239,12 +249,67 @@ namespace rct {
} }
} }
bool is_rct_bp_plus_legacy(int type)
{
switch (type)
{
case RCTTypeBulletproofPlus:
return true;
default:
return false;
}
}
bool is_rct_bp_plus_full(int type)
{
switch (type)
{
case RCTTypeBulletproofPlus_FullCommit:
return true;
default:
return false;
}
}
bool is_rct_bulletproof_plus_any(int type)
{
switch (type)
{
case RCTTypeBulletproofPlus:
case RCTTypeBulletproofPlus_FullCommit:
return true;
default:
return false;
}
}
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;
}
bool is_rct_clsag(int type) bool is_rct_clsag(int type)
{ {
switch (type) switch (type)
{ {
case RCTTypeCLSAG: case RCTTypeCLSAG:
case RCTTypeBulletproofPlus: case RCTTypeBulletproofPlus:
case RCTTypeBulletproofPlus_FullCommit:
return true; return true;
default: default:
return false; return false;

View File

@@ -279,8 +279,10 @@ namespace rct {
}; };
size_t n_bulletproof_amounts(const Bulletproof &proof); 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_max_amounts(const Bulletproof &proof);
size_t n_bulletproof_amounts(const std::vector<Bulletproof> &proofs); 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); size_t n_bulletproof_max_amounts(const std::vector<Bulletproof> &proofs);
size_t n_bulletproof_plus_amounts(const BulletproofPlus &proof); size_t n_bulletproof_plus_amounts(const BulletproofPlus &proof);
@@ -299,10 +301,13 @@ namespace rct {
RCTTypeNull = 0, RCTTypeNull = 0,
RCTTypeFull = 1, RCTTypeFull = 1,
RCTTypeSimple = 2, RCTTypeSimple = 2,
RCTTypeBulletproof = 3, RCTTypeFullBulletproof = 3,
RCTTypeBulletproof2 = 4, RCTTypeSimpleBulletproof = 4,
RCTTypeCLSAG = 5, RCTTypeBulletproof = 5,
RCTTypeBulletproofPlus = 6, RCTTypeBulletproof2 = 6,
RCTTypeCLSAG = 7,
RCTTypeBulletproofPlus = 8,
RCTTypeBulletproofPlus_FullCommit = 9,
}; };
enum RangeProofType { RangeProofBorromean, RangeProofBulletproof, RangeProofMultiOutputBulletproof, RangeProofPaddedBulletproof }; enum RangeProofType { RangeProofBorromean, RangeProofBulletproof, RangeProofMultiOutputBulletproof, RangeProofPaddedBulletproof };
struct RCTConfig { struct RCTConfig {
@@ -335,7 +340,7 @@ namespace rct {
FIELD(type) FIELD(type)
if (type == RCTTypeNull) if (type == RCTTypeNull)
return ar.good(); return ar.good();
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG && type != RCTTypeBulletproofPlus) if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeFullBulletproof && type != RCTTypeSimpleBulletproof && type != RCTTypeCLSAG && type != RCTTypeBulletproofPlus && type != RCTTypeBulletproofPlus_FullCommit)
return false; return false;
VARINT_FIELD(txnFee) VARINT_FIELD(txnFee)
// inputs/outputs not saved, only here for serialization help // inputs/outputs not saved, only here for serialization help
@@ -364,7 +369,7 @@ namespace rct {
return false; return false;
for (size_t i = 0; i < outputs; ++i) for (size_t i = 0; i < outputs; ++i)
{ {
if (type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus) if (type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeBulletproofPlus_FullCommit)
{ {
// Since RCTTypeBulletproof2 enote types, we don't serialize the blinding factor, and only serialize the // Since RCTTypeBulletproof2 enote types, we don't serialize the blinding factor, and only serialize the
// first 8 bytes of ecdhInfo[i].amount // first 8 bytes of ecdhInfo[i].amount
@@ -433,9 +438,24 @@ namespace rct {
return false; return false;
if (type == RCTTypeNull) if (type == RCTTypeNull)
return ar.good(); return ar.good();
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeCLSAG && type != RCTTypeBulletproofPlus) if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2 && type != RCTTypeFullBulletproof && type != RCTTypeSimpleBulletproof && type != RCTTypeCLSAG && type != RCTTypeBulletproofPlus && type != RCTTypeBulletproofPlus_FullCommit)
return false; return false;
if (type == RCTTypeBulletproofPlus) 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 == RCTTypeBulletproofPlus || type == RCTTypeBulletproofPlus_FullCommit)
{ {
uint32_t nbp = bulletproofs_plus.size(); uint32_t nbp = bulletproofs_plus.size();
VARINT_FIELD(nbp) VARINT_FIELD(nbp)
@@ -492,7 +512,7 @@ namespace rct {
ar.end_array(); ar.end_array();
} }
if (type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus) if (type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeBulletproofPlus_FullCommit)
{ {
ar.tag("CLSAGs"); ar.tag("CLSAGs");
ar.begin_array(); ar.begin_array();
@@ -538,7 +558,7 @@ namespace rct {
ar.begin_array(); ar.begin_array();
// we keep a byte for size of MGs, because we don't know whether this is // 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 // 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 || type == RCTTypeBulletproof2) ? inputs : 1; size_t mg_elements = (type == RCTTypeSimple || type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeSimpleBulletproof) ? inputs : 1;
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_elements, MGs); PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_elements, MGs);
if (MGs.size() != mg_elements) if (MGs.size() != mg_elements)
return false; return false;
@@ -556,7 +576,7 @@ namespace rct {
for (size_t j = 0; j < mixin + 1; ++j) for (size_t j = 0; j < mixin + 1; ++j)
{ {
ar.begin_array(); ar.begin_array();
size_t mg_ss2_elements = ((type == RCTTypeSimple || type == RCTTypeBulletproof || type == RCTTypeBulletproof2) ? 1 : inputs) + 1; size_t mg_ss2_elements = ((type == RCTTypeSimple || type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeSimpleBulletproof) ? 1 : inputs) + 1;
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_ss2_elements, MGs[i].ss[j]); PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_ss2_elements, MGs[i].ss[j]);
if (MGs[i].ss[j].size() != mg_ss2_elements) if (MGs[i].ss[j].size() != mg_ss2_elements)
return false; return false;
@@ -583,7 +603,7 @@ namespace rct {
} }
ar.end_array(); ar.end_array();
} }
if (type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus) if (type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeSimpleBulletproof || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeBulletproofPlus_FullCommit)
{ {
ar.tag("pseudoOuts"); ar.tag("pseudoOuts");
ar.begin_array(); ar.begin_array();
@@ -615,12 +635,12 @@ namespace rct {
keyV& get_pseudo_outs() keyV& get_pseudo_outs()
{ {
return type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus ? p.pseudoOuts : pseudoOuts; return type == RCTTypeBulletproof || type == RCTTypeSimpleBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeBulletproofPlus_FullCommit ? p.pseudoOuts : pseudoOuts;
} }
keyV const& get_pseudo_outs() const keyV const& get_pseudo_outs() const
{ {
return type == RCTTypeBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus ? p.pseudoOuts : pseudoOuts; return type == RCTTypeBulletproof || type == RCTTypeSimpleBulletproof || type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus || type == RCTTypeBulletproofPlus_FullCommit ? p.pseudoOuts : pseudoOuts;
} }
BEGIN_SERIALIZE_OBJECT() BEGIN_SERIALIZE_OBJECT()
@@ -732,9 +752,13 @@ namespace rct {
bool is_rct_simple(int type); bool is_rct_simple(int type);
bool is_rct_bulletproof(int type); bool is_rct_bulletproof(int type);
bool is_rct_bulletproof_plus(int type); bool is_rct_old_bulletproof(int type);
bool is_rct_new_bulletproof(int type);
bool is_rct_borromean(int type); bool is_rct_borromean(int type);
bool is_rct_clsag(int type); bool is_rct_clsag(int type);
bool is_rct_bp_plus_legacy(int type);
bool is_rct_bp_plus_full(int type);
bool is_rct_bulletproof_plus_any(int type);
static inline const rct::key &pk2rct(const crypto::public_key &pk) { return (const rct::key&)pk; } static inline const rct::key &pk2rct(const crypto::public_key &pk) { return (const rct::key&)pk; }
static inline const rct::key &sk2rct(const crypto::secret_key &sk) { return (const rct::key&)sk; } static inline const rct::key &sk2rct(const crypto::secret_key &sk) { return (const rct::key&)sk; }

View File

@@ -1939,6 +1939,7 @@ uint64_t WalletImpl::estimateTransactionFee(const std::vector<std::pair<std::str
m_wallet->use_fork_rules(8, 0), m_wallet->use_fork_rules(8, 0),
m_wallet->use_fork_rules(HF_VERSION_CLSAG, 0), m_wallet->use_fork_rules(HF_VERSION_CLSAG, 0),
m_wallet->use_fork_rules(HF_VERSION_BULLETPROOF_PLUS, 0), m_wallet->use_fork_rules(HF_VERSION_BULLETPROOF_PLUS, 0),
m_wallet->use_fork_rules(HF_VERSION_BP_PLUS_FULL_COMMIT, 0),
m_wallet->use_fork_rules(HF_VERSION_VIEW_TAGS, 0), m_wallet->use_fork_rules(HF_VERSION_VIEW_TAGS, 0),
m_wallet->get_base_fee(priority), m_wallet->get_base_fee(priority),
m_wallet->get_fee_quantization_mask()); m_wallet->get_fee_quantization_mask());

View File

@@ -789,7 +789,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, bool bulletproof, bool clsag, bool bulletproof_plus, bool use_view_tags) size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag, bool bulletproof_plus, bool bulletproof_plus_full_commit, bool use_view_tags)
{ {
size_t size = 0; size_t size = 0;
@@ -813,12 +813,12 @@ 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 || bulletproof_plus) if (bulletproof || bulletproof_plus || bulletproof_plus_full_commit)
{ {
size_t log_padded_outputs = 0; size_t log_padded_outputs = 0;
while ((1<<log_padded_outputs) < n_outputs) while ((1<<log_padded_outputs) < n_outputs)
++log_padded_outputs; ++log_padded_outputs;
size += (2 * (6 + log_padded_outputs) + (bulletproof_plus ? 6 : (4 + 5))) * 32 + 3; size += (2 * (6 + log_padded_outputs) + (bulletproof_plus_full_commit ? 6 : bulletproof_plus ? 6 : (4 + 5))) * 32 + 3;
} }
else else
size += (2*64*32+32+64*32) * n_outputs; size += (2*64*32+32+64*32) * n_outputs;
@@ -844,29 +844,29 @@ size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra
// txnFee // txnFee
size += 4; size += 4;
LOG_PRINT_L2("estimated " << (bulletproof_plus ? "bulletproof plus" : bulletproof ? "bulletproof" : "borromean") << " rct tx size for " << n_inputs << " inputs with ring size " << (mixin+1) << " and " << n_outputs << " outputs: " << size << " (" << ((32 * n_inputs/*+1*/) + 2 * 32 * (mixin+1) * n_inputs + 32 * n_outputs) << " saved)"); LOG_PRINT_L2("estimated " << (bulletproof_plus_full_commit ? "bulletproof plus full commit" : bulletproof_plus ? "bulletproof plus" : bulletproof ? "bulletproof" : "borromean") << " rct tx size for " << n_inputs << " inputs with ring size " << (mixin+1) << " and " << n_outputs << " outputs: " << size << " (" << ((32 * n_inputs/*+1*/) + 2 * 32 * (mixin+1) * n_inputs + 32 * n_outputs) << " saved)");
return size; return size;
} }
size_t estimate_tx_size(bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag, bool bulletproof_plus, bool use_view_tags) size_t estimate_tx_size(bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag, bool bulletproof_plus, bool bulletproof_plus_full_commit, bool use_view_tags)
{ {
if (use_rct) if (use_rct)
return estimate_rct_tx_size(n_inputs, mixin, n_outputs, extra_size, bulletproof, clsag, bulletproof_plus, use_view_tags); return estimate_rct_tx_size(n_inputs, mixin, n_outputs, extra_size, bulletproof, clsag, bulletproof_plus, bulletproof_plus_full_commit, use_view_tags);
else else
return n_inputs * (mixin+1) * APPROXIMATE_INPUT_BYTES + extra_size + (use_view_tags ? (n_outputs * sizeof(crypto::view_tag)) : 0); return n_inputs * (mixin+1) * APPROXIMATE_INPUT_BYTES + extra_size + (use_view_tags ? (n_outputs * sizeof(crypto::view_tag)) : 0);
} }
uint64_t estimate_tx_weight(bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag, bool bulletproof_plus, bool use_view_tags) uint64_t estimate_tx_weight(bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag, bool bulletproof_plus, bool bulletproof_plus_full_commit, bool use_view_tags)
{ {
size_t size = estimate_tx_size(use_rct, n_inputs, mixin, n_outputs, extra_size, bulletproof, clsag, bulletproof_plus, use_view_tags); size_t size = estimate_tx_size(use_rct, n_inputs, mixin, n_outputs, extra_size, bulletproof, clsag, bulletproof_plus, bulletproof_plus_full_commit, use_view_tags);
if (use_rct && (bulletproof || bulletproof_plus) && n_outputs > 2) if (use_rct && (bulletproof || bulletproof_plus || bulletproof_plus_full_commit) && n_outputs > 2)
{ {
const uint64_t bp_base = (32 * ((bulletproof_plus ? 6 : 9) + 7 * 2)) / 2; // notional size of a 2 output proof, normalized to 1 proof (ie, divided by 2) const uint64_t bp_base = (32 * ((bulletproof_plus_full_commit ? 6 : bulletproof_plus ? 6 : 9) + 7 * 2)) / 2; // notional size of a 2 output proof, normalized to 1 proof (ie, divided by 2)
size_t log_padded_outputs = 2; size_t log_padded_outputs = 2;
while ((1<<log_padded_outputs) < n_outputs) while ((1<<log_padded_outputs) < n_outputs)
++log_padded_outputs; ++log_padded_outputs;
uint64_t nlr = 2 * (6 + log_padded_outputs); uint64_t nlr = 2 * (6 + log_padded_outputs);
const uint64_t bp_size = 32 * ((bulletproof_plus ? 6 : 9) + nlr); const uint64_t bp_size = 32 * ((bulletproof_plus_full_commit ? 6 : bulletproof_plus ? 6 : 9) + nlr);
const uint64_t bp_clawback = (bp_base * (1<<log_padded_outputs) - bp_size) * 4 / 5; const uint64_t bp_clawback = (bp_base * (1<<log_padded_outputs) - bp_size) * 4 / 5;
MDEBUG("clawback on size " << size << ": " << bp_clawback); MDEBUG("clawback on size " << size << ": " << bp_clawback);
size += bp_clawback; size += bp_clawback;
@@ -884,6 +884,11 @@ uint8_t get_bulletproof_plus_fork()
return HF_VERSION_BULLETPROOF_PLUS; return HF_VERSION_BULLETPROOF_PLUS;
} }
uint8_t get_bulletproof_plus_full_commit_fork()
{
return HF_VERSION_BP_PLUS_FULL_COMMIT;
}
uint8_t get_clsag_fork() uint8_t get_clsag_fork()
{ {
return HF_VERSION_CLSAG; return HF_VERSION_CLSAG;
@@ -2195,12 +2200,15 @@ static uint64_t decodeRct(const rct::rctSig & rv, const crypto::key_derivation &
switch (rv.type) switch (rv.type)
{ {
case rct::RCTTypeSimple: case rct::RCTTypeSimple:
case rct::RCTTypeSimpleBulletproof:
case rct::RCTTypeBulletproof: case rct::RCTTypeBulletproof:
case rct::RCTTypeBulletproof2: case rct::RCTTypeBulletproof2:
case rct::RCTTypeCLSAG: case rct::RCTTypeCLSAG:
case rct::RCTTypeBulletproofPlus: case rct::RCTTypeBulletproofPlus:
case rct::RCTTypeBulletproofPlus_FullCommit:
return rct::decodeRctSimple(rv, rct::sk2rct(scalar1), i, mask, hwdev); return rct::decodeRctSimple(rv, rct::sk2rct(scalar1), i, mask, hwdev);
case rct::RCTTypeFull: case rct::RCTTypeFull:
case rct::RCTTypeFullBulletproof:
return rct::decodeRct(rv, rct::sk2rct(scalar1), i, mask, hwdev); return rct::decodeRct(rv, rct::sk2rct(scalar1), i, mask, hwdev);
default: default:
LOG_ERROR("Unsupported rct type: " << rv.type); LOG_ERROR("Unsupported rct type: " << rv.type);
@@ -8523,16 +8531,16 @@ bool wallet2::sign_multisig_tx_from_file(const std::string &filename, std::vecto
return sign_multisig_tx_to_file(exported_txs, filename, txids); return sign_multisig_tx_to_file(exported_txs, filename, txids);
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
uint64_t wallet2::estimate_fee(bool use_per_byte_fee, bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag, bool bulletproof_plus, bool use_view_tags, uint64_t base_fee, uint64_t fee_quantization_mask) uint64_t wallet2::estimate_fee(bool use_per_byte_fee, bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag, bool bulletproof_plus, bool bulletproof_plus_full_commit, bool use_view_tags, uint64_t base_fee, uint64_t fee_quantization_mask)
{ {
if (use_per_byte_fee) if (use_per_byte_fee)
{ {
const size_t estimated_tx_weight = estimate_tx_weight(use_rct, n_inputs, mixin, n_outputs, extra_size, bulletproof, clsag, bulletproof_plus, use_view_tags); const size_t estimated_tx_weight = estimate_tx_weight(use_rct, n_inputs, mixin, n_outputs, extra_size, bulletproof, clsag, bulletproof_plus, bulletproof_plus_full_commit, use_view_tags);
return calculate_fee_from_weight(base_fee, estimated_tx_weight, fee_quantization_mask); return calculate_fee_from_weight(base_fee, estimated_tx_weight, fee_quantization_mask);
} }
else else
{ {
const size_t estimated_tx_size = estimate_tx_size(use_rct, n_inputs, mixin, n_outputs, extra_size, bulletproof, clsag, bulletproof_plus, use_view_tags); const size_t estimated_tx_size = estimate_tx_size(use_rct, n_inputs, mixin, n_outputs, extra_size, bulletproof, clsag, bulletproof_plus, bulletproof_plus_full_commit, use_view_tags);
return calculate_fee(base_fee, estimated_tx_size); return calculate_fee(base_fee, estimated_tx_size);
} }
} }
@@ -11167,6 +11175,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
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(), 0); const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0);
const bool bulletproof_plus = use_fork_rules(get_bulletproof_plus_fork(), 0); const bool bulletproof_plus = use_fork_rules(get_bulletproof_plus_fork(), 0);
const bool bulletproof_plus_full_commit = use_fork_rules(get_bulletproof_plus_full_commit_fork(), 0);
const bool clsag = use_fork_rules(get_clsag_fork(), 0); const bool clsag = use_fork_rules(get_clsag_fork(), 0);
const rct::RCTConfig rct_config { const rct::RCTConfig rct_config {
rct::RangeProofPaddedBulletproof, rct::RangeProofPaddedBulletproof,
@@ -11215,7 +11224,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// early out if we know we can't make it anyway // 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 // 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 // ever changes, this might be missed, so let this go through
const uint64_t min_fee = (base_fee * estimate_tx_size(use_rct, 1, fake_outs_count, 2, extra.size(), bulletproof, clsag, bulletproof_plus, use_view_tags)); const uint64_t min_fee = (base_fee * estimate_tx_size(use_rct, 1, fake_outs_count, 2, extra.size(), bulletproof, clsag, bulletproof_plus, bulletproof_plus_full_commit, use_view_tags));
total_needed_money = needed_money + (subtract_fee_from_outputs.size() ? 0 : min_fee); total_needed_money = needed_money + (subtract_fee_from_outputs.size() ? 0 : min_fee);
uint64_t balance_subtotal = 0; uint64_t balance_subtotal = 0;
uint64_t unlocked_balance_subtotal = 0; uint64_t unlocked_balance_subtotal = 0;
@@ -11234,8 +11243,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
LOG_PRINT_L2("Candidate subaddress index for spending: " << i); LOG_PRINT_L2("Candidate subaddress index for spending: " << i);
// determine threshold for fractional amount // determine threshold for fractional amount
const size_t tx_weight_one_ring = estimate_tx_weight(use_rct, 1, fake_outs_count, 2, 0, bulletproof, clsag, bulletproof_plus, use_view_tags); const size_t tx_weight_one_ring = estimate_tx_weight(use_rct, 1, fake_outs_count, 2, 0, bulletproof, clsag, bulletproof_plus, bulletproof_plus_full_commit, use_view_tags);
const size_t tx_weight_two_rings = estimate_tx_weight(use_rct, 2, fake_outs_count, 2, 0, bulletproof, clsag, bulletproof_plus, use_view_tags); const size_t tx_weight_two_rings = estimate_tx_weight(use_rct, 2, fake_outs_count, 2, 0, bulletproof, clsag, bulletproof_plus, bulletproof_plus_full_commit, use_view_tags);
THROW_WALLET_EXCEPTION_IF(tx_weight_one_ring > tx_weight_two_rings, error::wallet_internal_error, "Estimated tx weight with 1 input is larger than with 2 inputs!"); THROW_WALLET_EXCEPTION_IF(tx_weight_one_ring > tx_weight_two_rings, error::wallet_internal_error, "Estimated tx weight with 1 input is larger than with 2 inputs!");
const size_t tx_weight_per_ring = tx_weight_two_rings - tx_weight_one_ring; const size_t tx_weight_per_ring = tx_weight_two_rings - tx_weight_one_ring;
const uint64_t fractional_threshold = (base_fee * tx_weight_per_ring) / (use_per_byte_fee ? 1 : 1024); const uint64_t fractional_threshold = (base_fee * tx_weight_per_ring) / (use_per_byte_fee ? 1 : 1024);
@@ -11329,7 +11338,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 = estimate_fee(use_per_byte_fee, use_rct, 2, fake_outs_count, 2, extra.size(), bulletproof, clsag, bulletproof_plus, use_view_tags, base_fee, fee_quantization_mask); uint64_t estimated_fee = estimate_fee(use_per_byte_fee, use_rct, 2, fake_outs_count, 2, extra.size(), bulletproof, clsag, bulletproof_plus, bulletproof_plus_full_commit, use_view_tags, base_fee, fee_quantization_mask);
total_needed_money = needed_money + (subtract_fee_from_outputs.size() ? 0 : estimated_fee); total_needed_money = needed_money + (subtract_fee_from_outputs.size() ? 0 : estimated_fee);
preferred_inputs = pick_preferred_rct_inputs(total_needed_money, subaddr_account, subaddr_indices); preferred_inputs = pick_preferred_rct_inputs(total_needed_money, subaddr_account, subaddr_indices);
if (!preferred_inputs.empty()) if (!preferred_inputs.empty())
@@ -11442,7 +11451,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_weight(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size()+1, extra.size(), bulletproof, clsag, bulletproof_plus, use_view_tags) < TX_WEIGHT_TARGET(upper_transaction_weight_limit)) while (!dsts.empty() && dsts[0].amount <= available_amount && estimate_tx_weight(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size()+1, extra.size(), bulletproof, clsag, bulletproof_plus, bulletproof_plus_full_commit, use_view_tags) < TX_WEIGHT_TARGET(upper_transaction_weight_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_nettype, dsts[0].is_subaddress, dsts[0].addr) << LOG_PRINT_L2("We can fully pay " << get_account_address_as_str(m_nettype, dsts[0].is_subaddress, dsts[0].addr) <<
@@ -11462,7 +11471,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
} }
if (!out_slots_exhausted && available_amount > 0 && !dsts.empty() && if (!out_slots_exhausted && available_amount > 0 && !dsts.empty() &&
estimate_tx_weight(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size()+1, extra.size(), bulletproof, clsag, bulletproof_plus, use_view_tags) < TX_WEIGHT_TARGET(upper_transaction_weight_limit)) { estimate_tx_weight(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size()+1, extra.size(), bulletproof, clsag, bulletproof_plus, bulletproof_plus_full_commit, use_view_tags) < TX_WEIGHT_TARGET(upper_transaction_weight_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_nettype, dsts[0].is_subaddress, dsts[0].addr) << LOG_PRINT_L2("We can partially pay " << get_account_address_as_str(m_nettype, 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));
@@ -11501,7 +11510,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
} }
else else
{ {
const size_t estimated_rct_tx_weight = estimate_tx_weight(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size()+1, extra.size(), bulletproof, clsag, bulletproof_plus, use_view_tags); const size_t estimated_rct_tx_weight = estimate_tx_weight(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size()+1, extra.size(), bulletproof, clsag, bulletproof_plus, bulletproof_plus_full_commit, use_view_tags);
try_tx = dsts.empty() || (estimated_rct_tx_weight >= TX_WEIGHT_TARGET(upper_transaction_weight_limit)); try_tx = dsts.empty() || (estimated_rct_tx_weight >= TX_WEIGHT_TARGET(upper_transaction_weight_limit));
THROW_WALLET_EXCEPTION_IF(try_tx && tx.dsts.empty(), error::tx_too_big, estimated_rct_tx_weight, upper_transaction_weight_limit); THROW_WALLET_EXCEPTION_IF(try_tx && tx.dsts.empty(), error::tx_too_big, estimated_rct_tx_weight, upper_transaction_weight_limit);
} }
@@ -11512,7 +11521,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
pending_tx test_ptx; pending_tx test_ptx;
const size_t num_outputs = get_num_outputs(tx.dsts, m_transfers, tx.selected_transfers); const size_t num_outputs = get_num_outputs(tx.dsts, m_transfers, tx.selected_transfers);
needed_fee = estimate_fee(use_per_byte_fee, use_rct ,tx.selected_transfers.size(), fake_outs_count, num_outputs, extra.size(), bulletproof, clsag, bulletproof_plus, use_view_tags, base_fee, fee_quantization_mask); needed_fee = estimate_fee(use_per_byte_fee, use_rct ,tx.selected_transfers.size(), fake_outs_count, num_outputs, extra.size(), bulletproof, clsag, bulletproof_plus, bulletproof_plus_full_commit, use_view_tags, base_fee, fee_quantization_mask);
auto try_carving_from_partial_payment = [&](uint64_t needed_fee, uint64_t available_for_fee) auto try_carving_from_partial_payment = [&](uint64_t needed_fee, uint64_t available_for_fee)
{ {
@@ -11820,11 +11829,12 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
const bool use_per_byte_fee = use_fork_rules(HF_VERSION_PER_BYTE_FEE, 0); const bool use_per_byte_fee = use_fork_rules(HF_VERSION_PER_BYTE_FEE, 0);
const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0); const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0);
const bool bulletproof_plus = use_fork_rules(get_bulletproof_plus_fork(), 0); const bool bulletproof_plus = use_fork_rules(get_bulletproof_plus_fork(), 0);
const bool bulletproof_plus_full_commit = use_fork_rules(get_bulletproof_plus_full_commit_fork(), 0);
const bool clsag = use_fork_rules(get_clsag_fork(), 0); const bool clsag = use_fork_rules(get_clsag_fork(), 0);
const bool use_view_tags = use_fork_rules(get_view_tag_fork(), 0); const bool use_view_tags = use_fork_rules(get_view_tag_fork(), 0);
const uint64_t base_fee = get_base_fee(priority); const uint64_t base_fee = get_base_fee(priority);
const size_t tx_weight_one_ring = estimate_tx_weight(use_rct, 1, fake_outs_count, 2, 0, bulletproof, clsag, bulletproof_plus, use_view_tags); const size_t tx_weight_one_ring = estimate_tx_weight(use_rct, 1, fake_outs_count, 2, 0, bulletproof, clsag, bulletproof_plus, bulletproof_plus_full_commit, use_view_tags);
const size_t tx_weight_two_rings = estimate_tx_weight(use_rct, 2, fake_outs_count, 2, 0, bulletproof, clsag, bulletproof_plus, use_view_tags); const size_t tx_weight_two_rings = estimate_tx_weight(use_rct, 2, fake_outs_count, 2, 0, bulletproof, clsag, bulletproof_plus, bulletproof_plus_full_commit, use_view_tags);
THROW_WALLET_EXCEPTION_IF(tx_weight_one_ring > tx_weight_two_rings, error::wallet_internal_error, "Estimated tx weight with 1 input is larger than with 2 inputs!"); THROW_WALLET_EXCEPTION_IF(tx_weight_one_ring > tx_weight_two_rings, error::wallet_internal_error, "Estimated tx weight with 1 input is larger than with 2 inputs!");
const size_t tx_weight_per_ring = tx_weight_two_rings - tx_weight_one_ring; const size_t tx_weight_per_ring = tx_weight_two_rings - tx_weight_one_ring;
const uint64_t fractional_threshold = (base_fee * tx_weight_per_ring) / (use_per_byte_fee ? 1 : 1024); const uint64_t fractional_threshold = (base_fee * tx_weight_per_ring) / (use_per_byte_fee ? 1 : 1024);
@@ -11933,6 +11943,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
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(), 0); const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0);
const bool bulletproof_plus = use_fork_rules(get_bulletproof_plus_fork(), 0); const bool bulletproof_plus = use_fork_rules(get_bulletproof_plus_fork(), 0);
const bool bulletproof_plus_full_commit = use_fork_rules(get_bulletproof_plus_full_commit_fork(), 0);
const bool clsag = use_fork_rules(get_clsag_fork(), 0); const bool clsag = use_fork_rules(get_clsag_fork(), 0);
const rct::RCTConfig rct_config { const rct::RCTConfig rct_config {
rct::RangeProofPaddedBulletproof, rct::RangeProofPaddedBulletproof,
@@ -11965,7 +11976,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
uint64_t fee_dust_threshold; uint64_t fee_dust_threshold;
if (use_fork_rules(HF_VERSION_PER_BYTE_FEE)) if (use_fork_rules(HF_VERSION_PER_BYTE_FEE))
{ {
const uint64_t estimated_tx_weight_with_one_extra_output = estimate_tx_weight(use_rct, tx.selected_transfers.size() + 1, fake_outs_count, tx.dsts.size()+1, extra.size(), bulletproof, clsag, bulletproof_plus, use_view_tags); const uint64_t estimated_tx_weight_with_one_extra_output = estimate_tx_weight(use_rct, tx.selected_transfers.size() + 1, fake_outs_count, tx.dsts.size()+1, extra.size(), bulletproof, clsag, bulletproof_plus, bulletproof_plus_full_commit, use_view_tags);
fee_dust_threshold = calculate_fee_from_weight(base_fee, estimated_tx_weight_with_one_extra_output, fee_quantization_mask); fee_dust_threshold = calculate_fee_from_weight(base_fee, estimated_tx_weight_with_one_extra_output, fee_quantization_mask);
} }
else else
@@ -11996,7 +12007,7 @@ 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_weight_limit); << upper_transaction_weight_limit);
const size_t estimated_rct_tx_weight = estimate_tx_weight(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size() + 2, extra.size(), bulletproof, clsag, bulletproof_plus, use_view_tags); const size_t estimated_rct_tx_weight = estimate_tx_weight(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size() + 2, extra.size(), bulletproof, clsag, bulletproof_plus, bulletproof_plus_full_commit, use_view_tags);
bool try_tx = (unused_dust_indices.empty() && unused_transfers_indices.empty()) || ( estimated_rct_tx_weight >= TX_WEIGHT_TARGET(upper_transaction_weight_limit)); bool try_tx = (unused_dust_indices.empty() && unused_transfers_indices.empty()) || ( estimated_rct_tx_weight >= TX_WEIGHT_TARGET(upper_transaction_weight_limit));
if (try_tx) { if (try_tx) {
@@ -12004,7 +12015,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
pending_tx test_ptx; pending_tx test_ptx;
const size_t num_outputs = get_num_outputs(tx.dsts, m_transfers, tx.selected_transfers); const size_t num_outputs = get_num_outputs(tx.dsts, m_transfers, tx.selected_transfers);
needed_fee = estimate_fee(use_per_byte_fee, use_rct, tx.selected_transfers.size(), fake_outs_count, num_outputs, extra.size(), bulletproof, clsag, bulletproof_plus, use_view_tags, base_fee, fee_quantization_mask); needed_fee = estimate_fee(use_per_byte_fee, use_rct, tx.selected_transfers.size(), fake_outs_count, num_outputs, extra.size(), bulletproof, clsag, bulletproof_plus, bulletproof_plus_full_commit, use_view_tags, base_fee, fee_quantization_mask);
// add N - 1 outputs for correct initial fee estimation // add N - 1 outputs for correct initial fee estimation
for (size_t i = 0; i < ((outputs > 1) ? outputs - 1 : outputs); ++i) for (size_t i = 0; i < ((outputs > 1) ? outputs - 1 : outputs); ++i)
@@ -12853,8 +12864,10 @@ void wallet2::check_tx_key_helper(const cryptonote::transaction &tx, const crypt
crypto::secret_key scalar1; crypto::secret_key scalar1;
crypto::derivation_to_scalar(found_derivation, n, scalar1); crypto::derivation_to_scalar(found_derivation, n, scalar1);
rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[n]; rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[n];
rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1), tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus); rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1), tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus_FullCommit);
const rct::key C = tx.rct_signatures.outPk[n].mask; rct::key C = tx.rct_signatures.outPk[n].mask;
if (rct::is_rct_bp_plus_legacy(tx.rct_signatures.type))
C = rct::scalarmult8(C);
rct::key Ctmp; rct::key Ctmp;
THROW_WALLET_EXCEPTION_IF(sc_check(ecdh_info.mask.bytes) != 0, error::wallet_internal_error, "Bad ECDH input mask"); THROW_WALLET_EXCEPTION_IF(sc_check(ecdh_info.mask.bytes) != 0, error::wallet_internal_error, "Bad ECDH input mask");
THROW_WALLET_EXCEPTION_IF(sc_check(ecdh_info.amount.bytes) != 0, error::wallet_internal_error, "Bad ECDH input amount"); THROW_WALLET_EXCEPTION_IF(sc_check(ecdh_info.amount.bytes) != 0, error::wallet_internal_error, "Bad ECDH input amount");
@@ -13543,7 +13556,7 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr
crypto::secret_key shared_secret; crypto::secret_key shared_secret;
crypto::derivation_to_scalar(derivation, proof.index_in_tx, shared_secret); crypto::derivation_to_scalar(derivation, proof.index_in_tx, shared_secret);
rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[proof.index_in_tx]; rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[proof.index_in_tx];
rct::ecdhDecode(ecdh_info, rct::sk2rct(shared_secret), tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus); rct::ecdhDecode(ecdh_info, rct::sk2rct(shared_secret), tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus_FullCommit);
amount = rct::h2d(ecdh_info.amount); amount = rct::h2d(ecdh_info.amount);
} }
total += amount; total += amount;
@@ -16199,10 +16212,11 @@ std::pair<size_t, uint64_t> wallet2::estimate_tx_size_and_weight(bool use_rct, i
const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0); const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0);
const bool bulletproof_plus = use_fork_rules(get_bulletproof_plus_fork(), 0); const bool bulletproof_plus = use_fork_rules(get_bulletproof_plus_fork(), 0);
const bool bulletproof_plus_full_commit = use_fork_rules(get_bulletproof_plus_full_commit_fork(), 0);
const bool clsag = use_fork_rules(get_clsag_fork(), 0); const bool clsag = use_fork_rules(get_clsag_fork(), 0);
const bool use_view_tags = use_fork_rules(get_view_tag_fork(), 0); const bool use_view_tags = use_fork_rules(get_view_tag_fork(), 0);
size_t size = estimate_tx_size(use_rct, n_inputs, ring_size - 1, n_outputs, extra_size, bulletproof, clsag, bulletproof_plus, use_view_tags); size_t size = estimate_tx_size(use_rct, n_inputs, ring_size - 1, n_outputs, extra_size, bulletproof, clsag, bulletproof_plus, bulletproof_plus_full_commit, use_view_tags);
uint64_t weight = estimate_tx_weight(use_rct, n_inputs, ring_size - 1, n_outputs, extra_size, bulletproof, clsag, bulletproof_plus, use_view_tags); uint64_t weight = estimate_tx_weight(use_rct, n_inputs, ring_size - 1, n_outputs, extra_size, bulletproof, clsag, bulletproof_plus, bulletproof_plus_full_commit, use_view_tags);
return std::make_pair(size, weight); return std::make_pair(size, weight);
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------

View File

@@ -1665,7 +1665,7 @@ private:
std::vector<std::pair<uint64_t, uint64_t>> estimate_backlog(const std::vector<std::pair<double, double>> &fee_levels); std::vector<std::pair<uint64_t, uint64_t>> estimate_backlog(const std::vector<std::pair<double, double>> &fee_levels);
std::vector<std::pair<uint64_t, uint64_t>> estimate_backlog(uint64_t min_tx_weight, uint64_t max_tx_weight, const std::vector<uint64_t> &fees); std::vector<std::pair<uint64_t, uint64_t>> estimate_backlog(uint64_t min_tx_weight, uint64_t max_tx_weight, const std::vector<uint64_t> &fees);
static uint64_t estimate_fee(bool use_per_byte_fee, bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag, bool bulletproof_plus, bool use_view_tags, uint64_t base_fee, uint64_t fee_quantization_mask); static uint64_t estimate_fee(bool use_per_byte_fee, bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, bool clsag, bool bulletproof_plus, bool bulletproof_plus_full_commit, bool use_view_tags, uint64_t base_fee, uint64_t fee_quantization_mask);
uint64_t get_fee_multiplier(uint32_t priority, int fee_algorithm = -1); uint64_t get_fee_multiplier(uint32_t priority, int fee_algorithm = -1);
uint64_t get_base_fee(uint32_t priority); uint64_t get_base_fee(uint32_t priority);
uint64_t get_base_fee(); uint64_t get_base_fee();

View File

@@ -193,7 +193,7 @@ bool gen_bpp_tx_validation_base::check_bpp(const cryptonote::transaction &tx, si
{ {
DEFINE_TESTS_ERROR_CONTEXT(context); DEFINE_TESTS_ERROR_CONTEXT(context);
CHECK_TEST_CONDITION(tx.version >= 2); CHECK_TEST_CONDITION(tx.version >= 2);
CHECK_TEST_CONDITION(rct::is_rct_bulletproof_plus(tx.rct_signatures.type)); CHECK_TEST_CONDITION(rct::is_rct_bulletproof_plus_any(tx.rct_signatures.type));
size_t n_sizes = 0, n_amounts = 0; size_t n_sizes = 0, n_amounts = 0;
for (size_t n = 0; n < tx_idx; ++n) for (size_t n = 0; n < tx_idx; ++n)
{ {
@@ -312,7 +312,7 @@ bool gen_bpp_tx_invalid_not_enough_proofs::generate(std::vector<test_event_entry
const uint64_t amounts_paid[] = {5000, 5000, (uint64_t)-1}; const uint64_t amounts_paid[] = {5000, 5000, (uint64_t)-1};
const rct::RCTConfig rct_config[] = { { rct::RangeProofBulletproof, 4 } }; const rct::RCTConfig rct_config[] = { { rct::RangeProofBulletproof, 4 } };
return generate_with(events, mixin, 1, amounts_paid, false, rct_config, HF_VERSION_BULLETPROOF_PLUS, NULL, [&](cryptonote::transaction &tx, size_t idx){ return generate_with(events, mixin, 1, amounts_paid, false, rct_config, HF_VERSION_BULLETPROOF_PLUS, NULL, [&](cryptonote::transaction &tx, size_t idx){
CHECK_TEST_CONDITION(tx.rct_signatures.type == rct::RCTTypeBulletproofPlus); CHECK_TEST_CONDITION(tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus_FullCommit);
CHECK_TEST_CONDITION(!tx.rct_signatures.p.bulletproofs_plus.empty()); CHECK_TEST_CONDITION(!tx.rct_signatures.p.bulletproofs_plus.empty());
tx.rct_signatures.p.bulletproofs_plus.pop_back(); tx.rct_signatures.p.bulletproofs_plus.pop_back();
CHECK_TEST_CONDITION(!tx.rct_signatures.p.bulletproofs_plus.empty()); CHECK_TEST_CONDITION(!tx.rct_signatures.p.bulletproofs_plus.empty());
@@ -327,7 +327,7 @@ bool gen_bpp_tx_invalid_empty_proofs::generate(std::vector<test_event_entry>& ev
const uint64_t amounts_paid[] = {50000, 50000, (uint64_t)-1}; const uint64_t amounts_paid[] = {50000, 50000, (uint64_t)-1};
const rct::RCTConfig rct_config[] = { { rct::RangeProofBulletproof, 4 } }; const rct::RCTConfig rct_config[] = { { rct::RangeProofBulletproof, 4 } };
return generate_with(events, mixin, 1, amounts_paid, false, rct_config, HF_VERSION_BULLETPROOF_PLUS, NULL, [&](cryptonote::transaction &tx, size_t idx){ return generate_with(events, mixin, 1, amounts_paid, false, rct_config, HF_VERSION_BULLETPROOF_PLUS, NULL, [&](cryptonote::transaction &tx, size_t idx){
CHECK_TEST_CONDITION(tx.rct_signatures.type == rct::RCTTypeBulletproofPlus); CHECK_TEST_CONDITION(tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus_FullCommit);
tx.rct_signatures.p.bulletproofs_plus.clear(); tx.rct_signatures.p.bulletproofs_plus.clear();
return true; return true;
}); });
@@ -340,7 +340,7 @@ bool gen_bpp_tx_invalid_too_many_proofs::generate(std::vector<test_event_entry>&
const uint64_t amounts_paid[] = {10000, (uint64_t)-1}; const uint64_t amounts_paid[] = {10000, (uint64_t)-1};
const rct::RCTConfig rct_config[] = { { rct::RangeProofBulletproof, 4 } }; const rct::RCTConfig rct_config[] = { { rct::RangeProofBulletproof, 4 } };
return generate_with(events, mixin, 1, amounts_paid, false, rct_config, HF_VERSION_BULLETPROOF_PLUS, NULL, [&](cryptonote::transaction &tx, size_t idx){ return generate_with(events, mixin, 1, amounts_paid, false, rct_config, HF_VERSION_BULLETPROOF_PLUS, NULL, [&](cryptonote::transaction &tx, size_t idx){
CHECK_TEST_CONDITION(tx.rct_signatures.type == rct::RCTTypeBulletproofPlus); CHECK_TEST_CONDITION(tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus_FullCommit);
CHECK_TEST_CONDITION(!tx.rct_signatures.p.bulletproofs_plus.empty()); CHECK_TEST_CONDITION(!tx.rct_signatures.p.bulletproofs_plus.empty());
tx.rct_signatures.p.bulletproofs_plus.push_back(tx.rct_signatures.p.bulletproofs_plus.back()); tx.rct_signatures.p.bulletproofs_plus.push_back(tx.rct_signatures.p.bulletproofs_plus.back());
return true; return true;
@@ -354,7 +354,7 @@ bool gen_bpp_tx_invalid_wrong_amount::generate(std::vector<test_event_entry>& ev
const uint64_t amounts_paid[] = {10000, (uint64_t)-1}; const uint64_t amounts_paid[] = {10000, (uint64_t)-1};
const rct::RCTConfig rct_config[] = { { rct::RangeProofBulletproof, 4 } }; const rct::RCTConfig rct_config[] = { { rct::RangeProofBulletproof, 4 } };
return generate_with(events, mixin, 1, amounts_paid, false, rct_config, HF_VERSION_BULLETPROOF_PLUS, NULL, [&](cryptonote::transaction &tx, size_t idx){ return generate_with(events, mixin, 1, amounts_paid, false, rct_config, HF_VERSION_BULLETPROOF_PLUS, NULL, [&](cryptonote::transaction &tx, size_t idx){
CHECK_TEST_CONDITION(tx.rct_signatures.type == rct::RCTTypeBulletproofPlus); CHECK_TEST_CONDITION(tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus_FullCommit);
CHECK_TEST_CONDITION(!tx.rct_signatures.p.bulletproofs_plus.empty()); CHECK_TEST_CONDITION(!tx.rct_signatures.p.bulletproofs_plus.empty());
tx.rct_signatures.p.bulletproofs_plus.back() = rct::bulletproof_plus_PROVE(1000, rct::skGen()); tx.rct_signatures.p.bulletproofs_plus.back() = rct::bulletproof_plus_PROVE(1000, rct::skGen());
return true; return true;

View File

@@ -434,8 +434,10 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector<test_event_entry
crypto::secret_key scalar1; crypto::secret_key scalar1;
crypto::derivation_to_scalar(derivation, n, scalar1); crypto::derivation_to_scalar(derivation, n, scalar1);
rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[n]; rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[n];
rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1), tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus); rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1), tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus_FullCommit);
rct::key C = tx.rct_signatures.outPk[n].mask; rct::key C = tx.rct_signatures.outPk[n].mask;
if (rct::is_rct_bp_plus_legacy(tx.rct_signatures.type))
C = rct::scalarmult8(C);
rct::addKeys2(Ctmp, ecdh_info.mask, ecdh_info.amount, rct::H); rct::addKeys2(Ctmp, ecdh_info.mask, ecdh_info.amount, rct::H);
CHECK_AND_ASSERT_MES(rct::equalKeys(C, Ctmp), false, "Failed to decode amount"); CHECK_AND_ASSERT_MES(rct::equalKeys(C, Ctmp), false, "Failed to decode amount");
amount += rct::h2d(ecdh_info.amount); amount += rct::h2d(ecdh_info.amount);

View File

@@ -561,7 +561,7 @@ static void expand_tsx(cryptonote::transaction &tx)
rv.p.MGs[n].II[0] = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image); rv.p.MGs[n].II[0] = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image);
} }
} }
else if (rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus) else if (rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus || rv.type == rct::RCTTypeBulletproofPlus_FullCommit)
{ {
if (!tx.pruned) if (!tx.pruned)
{ {