aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_basic
diff options
context:
space:
mode:
authormoneromooo-monero <moneromooo-monero@users.noreply.github.com>2020-12-17 11:57:53 +0000
committermoneromooo-monero <moneromooo-monero@users.noreply.github.com>2022-04-05 18:50:17 +0000
commita0d80b1f95cee64edfeba799f4fe9b8fb2ef4f43 (patch)
treeac0526f8b6747105010dacc20b3cd70e18ca993f /src/cryptonote_basic
parentUpdates from security audit (diff)
downloadmonero-a0d80b1f95cee64edfeba799f4fe9b8fb2ef4f43.tar.xz
plug bulletproofs plus into consensus
Diffstat (limited to 'src/cryptonote_basic')
-rw-r--r--src/cryptonote_basic/cryptonote_boost_serialization.h32
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.cpp47
2 files changed, 65 insertions, 14 deletions
diff --git a/src/cryptonote_basic/cryptonote_boost_serialization.h b/src/cryptonote_basic/cryptonote_boost_serialization.h
index c6b81b094..24d452083 100644
--- a/src/cryptonote_basic/cryptonote_boost_serialization.h
+++ b/src/cryptonote_basic/cryptonote_boost_serialization.h
@@ -228,6 +228,20 @@ namespace boost
}
template <class Archive>
+ inline void serialize(Archive &a, rct::BulletproofPlus &x, const boost::serialization::version_type ver)
+ {
+ a & x.V;
+ a & x.A;
+ a & x.A1;
+ a & x.B;
+ a & x.r1;
+ a & x.s1;
+ a & x.d1;
+ a & x.L;
+ a & x.R;
+ }
+
+ template <class Archive>
inline void serialize(Archive &a, rct::boroSig &x, const boost::serialization::version_type ver)
{
a & x.s0;
@@ -305,7 +319,7 @@ namespace boost
a & x.type;
if (x.type == rct::RCTTypeNull)
return;
- if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2 && x.type != rct::RCTTypeCLSAG)
+ 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)
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type");
// a & x.message; message is not serialized, as it can be reconstructed from the tx data
// a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
@@ -321,7 +335,11 @@ namespace boost
{
a & x.rangeSigs;
if (x.rangeSigs.empty())
+ {
a & x.bulletproofs;
+ if (ver >= 2u)
+ a & x.bulletproofs_plus;
+ }
a & x.MGs;
if (ver >= 1u)
a & x.CLSAGs;
@@ -335,7 +353,7 @@ namespace boost
a & x.type;
if (x.type == rct::RCTTypeNull)
return;
- if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2 && x.type != rct::RCTTypeCLSAG)
+ 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)
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type");
// a & x.message; message is not serialized, as it can be reconstructed from the tx data
// a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
@@ -347,11 +365,15 @@ namespace boost
//--------------
a & x.p.rangeSigs;
if (x.p.rangeSigs.empty())
+ {
a & x.p.bulletproofs;
+ if (ver >= 2u)
+ a & x.p.bulletproofs_plus;
+ }
a & x.p.MGs;
if (ver >= 1u)
a & x.p.CLSAGs;
- if (x.type == rct::RCTTypeBulletproof || x.type == rct::RCTTypeBulletproof2 || x.type == rct::RCTTypeCLSAG)
+ if (x.type == rct::RCTTypeBulletproof || x.type == rct::RCTTypeBulletproof2 || x.type == rct::RCTTypeCLSAG || x.type == rct::RCTTypeBulletproofPlus)
a & x.p.pseudoOuts;
}
@@ -392,6 +414,6 @@ namespace boost
}
}
-BOOST_CLASS_VERSION(rct::rctSigPrunable, 1)
-BOOST_CLASS_VERSION(rct::rctSig, 1)
+BOOST_CLASS_VERSION(rct::rctSigPrunable, 2)
+BOOST_CLASS_VERSION(rct::rctSig, 2)
BOOST_CLASS_VERSION(rct::multisig_out, 1)
diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp
index 835f59d69..8c10fad1f 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.cpp
+++ b/src/cryptonote_basic/cryptonote_format_utils.cpp
@@ -105,7 +105,9 @@ namespace cryptonote
uint64_t get_transaction_weight_clawback(const transaction &tx, size_t n_padded_outputs)
{
- const uint64_t bp_base = 368;
+ const rct::rctSig &rv = tx.rct_signatures;
+ const bool plus = rv.type == rct::RCTTypeBulletproofPlus;
+ 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();
if (n_padded_outputs <= 2)
return 0;
@@ -113,7 +115,7 @@ namespace cryptonote
while ((1u << nlr) < n_padded_outputs)
++nlr;
nlr += 6;
- const size_t bp_size = 32 * (9 + 2 * nlr);
+ const size_t bp_size = 32 * ((plus ? 6 : 9) + 2 * nlr);
CHECK_AND_ASSERT_THROW_MES_L1(n_outputs <= BULLETPROOF_MAX_OUTPUTS, "maximum number of outputs is " + std::to_string(BULLETPROOF_MAX_OUTPUTS) + " per transaction");
CHECK_AND_ASSERT_THROW_MES_L1(bp_base * n_padded_outputs >= bp_size, "Invalid bulletproof clawback: bp_base " + std::to_string(bp_base) + ", n_padded_outputs "
+ std::to_string(n_padded_outputs) + ", bp_size " + std::to_string(bp_size));
@@ -164,7 +166,32 @@ namespace cryptonote
if (!base_only)
{
const bool bulletproof = rct::is_rct_bulletproof(rv.type);
- if (bulletproof)
+ const bool bulletproof_plus = rct::is_rct_bulletproof_plus(rv.type);
+ if (bulletproof_plus)
+ {
+ if (rv.p.bulletproofs_plus.size() != 1)
+ {
+ LOG_PRINT_L1("Failed to parse transaction from blob, bad bulletproofs_plus size in tx " << get_transaction_hash(tx));
+ return false;
+ }
+ if (rv.p.bulletproofs_plus[0].L.size() < 6)
+ {
+ LOG_PRINT_L1("Failed to parse transaction from blob, bad bulletproofs_plus L size in tx " << get_transaction_hash(tx));
+ return false;
+ }
+ const size_t max_outputs = rct::n_bulletproof_plus_max_amounts(rv.p.bulletproofs_plus[0]);
+ if (max_outputs < tx.vout.size())
+ {
+ LOG_PRINT_L1("Failed to parse transaction from blob, bad bulletproofs_plus max outputs in tx " << get_transaction_hash(tx));
+ return false;
+ }
+ const size_t n_amounts = tx.vout.size();
+ CHECK_AND_ASSERT_MES(n_amounts == rv.outPk.size(), false, "Internal error filling out V");
+ rv.p.bulletproofs_plus[0].V.resize(n_amounts);
+ for (size_t i = 0; i < n_amounts; ++i)
+ rv.p.bulletproofs_plus[0].V[i] = rct::scalarmultKey(rv.outPk[i].mask, rct::INV_EIGHT);
+ }
+ else if (bulletproof)
{
if (rv.p.bulletproofs.size() != 1)
{
@@ -419,9 +446,11 @@ namespace cryptonote
if (tx.version < 2)
return blob_size;
const rct::rctSig &rv = tx.rct_signatures;
- if (!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);
+ if (!bulletproof && !bulletproof_plus)
return blob_size;
- const size_t n_padded_outputs = 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);
CHECK_AND_ASSERT_THROW_MES_L1(bp_clawback <= std::numeric_limits<uint64_t>::max() - blob_size, "Weight overflow");
return blob_size + bp_clawback;
@@ -431,8 +460,8 @@ 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.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,
- std::numeric_limits<uint64_t>::max(), "get_pruned_transaction_weight does not support older range proof types");
+ CHECK_AND_ASSERT_MES(tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus,
+ 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[0].type() == typeid(cryptonote::txin_to_key), std::numeric_limits<uint64_t>::max(), "empty vin");
@@ -450,12 +479,12 @@ namespace cryptonote
while ((n_padded_outputs = (1u << nrl)) < tx.vout.size())
++nrl;
nrl += 6;
- extra = 32 * (9 + 2 * nrl) + 2;
+ extra = 32 * ((rct::is_rct_bulletproof_plus(tx.rct_signatures.type) ? 6 : 9) + 2 * nrl) + 2;
weight += extra;
// calculate deterministic CLSAG/MLSAG data size
const size_t ring_size = boost::get<cryptonote::txin_to_key>(tx.vin[0]).key_offsets.size();
- if (tx.rct_signatures.type == rct::RCTTypeCLSAG)
+ if (rct::is_rct_clsag(tx.rct_signatures.type))
extra = tx.vin.size() * (ring_size + 2) * 32;
else
extra = tx.vin.size() * (ring_size * (1 + 1) * 32 + 32 /* cc */);