aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_core
diff options
context:
space:
mode:
authormoneromooo-monero <moneromooo-monero@users.noreply.github.com>2016-06-29 18:18:18 +0100
committermoneromooo-monero <moneromooo-monero@users.noreply.github.com>2016-08-28 21:28:55 +0100
commit20e50ec7f7f4104b5eb177aa30df4f5d4db9c8c3 (patch)
tree1f18f1130c9c553b7b103d035e6d829ec182011e /src/cryptonote_core
parentAdd rct core tests (diff)
downloadmonero-20e50ec7f7f4104b5eb177aa30df4f5d4db9c8c3.tar.xz
ringct: do not serialize what can be reconstructed
The mixRing (output keys and commitments) and II fields (key images) can be reconstructed from vin data. This saves some modest amount of space in the tx.
Diffstat (limited to 'src/cryptonote_core')
-rw-r--r--src/cryptonote_core/blockchain.cpp87
-rw-r--r--src/cryptonote_core/cryptonote_boost_serialization.h18
2 files changed, 81 insertions, 24 deletions
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 0d7294ffd..82bc6c0d4 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -2461,6 +2461,13 @@ bool Blockchain::check_tx_inputs(const transaction& tx, tx_verification_context
else
{
// from version 2, check ringct signatures
+ rct::ctkeyM reconstructed_mixRing;
+ rct::keyV reconstructed_II;
+
+ // if the tx already has a non empty mixRing and/or II, use them,
+ // else reconstruct them
+ const rct::ctkeyM &mixRing = tx.rct_signatures.mixRing.empty() ? reconstructed_mixRing : tx.rct_signatures.mixRing;
+ const rct::keyV &II = tx.rct_signatures.MG.II.size() == 1 ? reconstructed_II : tx.rct_signatures.MG.II;
// RCT needs the same mixin for all inputs
for (size_t n = 1; n < pubkeys.size(); ++n)
@@ -2472,35 +2479,74 @@ bool Blockchain::check_tx_inputs(const transaction& tx, tx_verification_context
}
}
- bool size_matches = true;
- for (size_t i = 0; i < pubkeys.size(); ++i)
- size_matches &= pubkeys[i].size() == tx.rct_signatures.mixRing.size();
- for (size_t i = 0; i < tx.rct_signatures.mixRing.size(); ++i)
- size_matches &= pubkeys.size() == tx.rct_signatures.mixRing[i].size();
- if (!size_matches)
+ if (tx.rct_signatures.mixRing.empty())
{
- LOG_PRINT_L1("Failed to check ringct signatures: mismatched pubkeys/mixRing size");
- return false;
+ reconstructed_mixRing.resize(pubkeys[0].size());
+ for (size_t n = 0; n < pubkeys.size(); ++n)
+ {
+ for (size_t m = 0; m < pubkeys[n].size(); ++m)
+ {
+ reconstructed_mixRing[m].push_back(pubkeys[n][m]);
+ }
+ }
}
- for (size_t n = 0; n < pubkeys.size(); ++n)
+ if (tx.rct_signatures.MG.II.size() == 1)
{
- for (size_t m = 0; m < pubkeys[n].size(); ++m)
+ reconstructed_II.resize(tx.vin.size());
+ for (size_t n = 0; n < tx.vin.size(); ++n)
{
- if (pubkeys[n][m].dest != rct::rct2pk(tx.rct_signatures.mixRing[m][n].dest))
- {
- LOG_PRINT_L1("Failed to check ringct signatures: mismatched pubkey at vin " << n << ", index " << m);
- return false;
- }
- if (pubkeys[n][m].mask != rct::rct2pk(tx.rct_signatures.mixRing[m][n].mask))
+ reconstructed_II[n] = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image);
+ }
+ reconstructed_II.push_back(tx.rct_signatures.MG.II.back());
+ }
+
+ // check all this, either recontructed (so should really pass), or not
+ {
+ bool size_matches = true;
+ for (size_t i = 0; i < pubkeys.size(); ++i)
+ size_matches &= pubkeys[i].size() == mixRing.size();
+ for (size_t i = 0; i < tx.rct_signatures.mixRing.size(); ++i)
+ size_matches &= pubkeys.size() == mixRing[i].size();
+ if (!size_matches)
+ {
+ LOG_PRINT_L1("Failed to check ringct signatures: mismatched pubkeys/mixRing size");
+ return false;
+ }
+
+ for (size_t n = 0; n < pubkeys.size(); ++n)
+ {
+ for (size_t m = 0; m < pubkeys[n].size(); ++m)
{
- LOG_PRINT_L1("Failed to check ringct signatures: mismatched commitment at vin " << n << ", index " << m);
- return false;
+ if (pubkeys[n][m].dest != rct::rct2pk(mixRing[m][n].dest))
+ {
+ LOG_PRINT_L1("Failed to check ringct signatures: mismatched pubkey at vin " << n << ", index " << m);
+ return false;
+ }
+ if (pubkeys[n][m].mask != rct::rct2pk(mixRing[m][n].mask))
+ {
+ LOG_PRINT_L1("Failed to check ringct signatures: mismatched commitment at vin " << n << ", index " << m);
+ return false;
+ }
}
}
}
- if (!rct::verRct(tx.rct_signatures))
+ if (II.size() != 1 + tx.vin.size())
+ {
+ LOG_PRINT_L1("Failed to check ringct signatures: mismatched II/vin sizes");
+ return false;
+ }
+ for (size_t n = 0; n < tx.vin.size(); ++n)
+ {
+ if (memcmp(&boost::get<txin_to_key>(tx.vin[n]).k_image, &II[n], 32))
+ {
+ LOG_PRINT_L1("Failed to check ringct signatures: mismatched II/vin sizes");
+ return false;
+ }
+ }
+
+ if (!rct::verRct(tx.rct_signatures, mixRing, II, rct::hash2rct(tx_prefix_hash)))
{
LOG_PRINT_L1("Failed to check ringct signatures!");
return false;
@@ -2613,7 +2659,8 @@ bool Blockchain::check_tx_input(size_t tx_version, const txin_to_key& txin, cons
}
else
{
- CHECK_AND_ASSERT_MES(rct_signatures.mixRing.size() == output_keys.size(), false, "internal error: tx rct signatures count=" << sig.size() << " mismatch with outputs keys count for inputs=" << output_keys.size());
+ // rct signatures may be empty (and will be reconstructed later in the caller if so)
+ CHECK_AND_ASSERT_MES(rct_signatures.mixRing.empty() || rct_signatures.mixRing.size() == output_keys.size(), false, "internal error: tx rct signatures count=" << sig.size() << " mismatch with outputs keys count for inputs=" << output_keys.size());
}
return true;
}
diff --git a/src/cryptonote_core/cryptonote_boost_serialization.h b/src/cryptonote_core/cryptonote_boost_serialization.h
index 6eeb66ec8..ccdd55883 100644
--- a/src/cryptonote_core/cryptonote_boost_serialization.h
+++ b/src/cryptonote_core/cryptonote_boost_serialization.h
@@ -37,6 +37,8 @@
#include <boost/serialization/map.hpp>
#include <boost/foreach.hpp>
#include <boost/serialization/is_bitwise_serializable.hpp>
+#include <boost/archive/binary_iarchive.hpp>
+#include <boost/archive/binary_oarchive.hpp>
#include "cryptonote_basic.h"
#include "common/unordered_containers_boost_serialization.h"
#include "crypto/crypto.h"
@@ -196,12 +198,19 @@ namespace boost
a & x.s;
}
- template <class Archive>
- inline void serialize(Archive &a, rct::mgSig &x, const boost::serialization::version_type ver)
+ inline void serialize(boost::archive::binary_iarchive &a, rct::mgSig &x, const boost::serialization::version_type ver)
+ {
+ a & x.ss;
+ a & x.cc;
+ x.II.resize(1);
+ a & x.II[0];
+ }
+
+ inline void serialize(boost::archive::binary_oarchive &a, rct::mgSig &x, const boost::serialization::version_type ver)
{
a & x.ss;
a & x.cc;
- a & x.II;
+ a & x.II.back();
}
template <class Archive>
@@ -217,10 +226,11 @@ namespace boost
{
a & x.rangeSigs;
a & x.MG;
- a & x.mixRing;
+ // a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
a & x.ecdhInfo;
a & x.outPk;
a & x.txnFee;
+ // a & x.bash_hash; bash_hash is not serialized, as it can be reconstructed from the tx data
}
}
}