aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_core
diff options
context:
space:
mode:
authormoneromooo-monero <moneromooo-monero@users.noreply.github.com>2016-07-10 12:57:22 +0100
committermoneromooo-monero <moneromooo-monero@users.noreply.github.com>2016-08-28 21:29:20 +0100
commita4d4d6194bf9a0826806521d72a7fec5e506a677 (patch)
treecff98fea187e5eaf765851e31e691e3f4f58f73f /src/cryptonote_core
parentserialization: add override for serializing bool (diff)
downloadmonero-a4d4d6194bf9a0826806521d72a7fec5e506a677.tar.xz
integrate simple rct api
Diffstat (limited to 'src/cryptonote_core')
-rw-r--r--src/cryptonote_core/blockchain.cpp212
-rw-r--r--src/cryptonote_core/cryptonote_basic.h12
-rw-r--r--src/cryptonote_core/cryptonote_boost_serialization.h21
-rw-r--r--src/cryptonote_core/cryptonote_format_utils.cpp86
4 files changed, 229 insertions, 102 deletions
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index bef880627..456a78eaf 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -2462,95 +2462,193 @@ 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)
+ // obviously, the original and simple rct APIs use a mixRing that's indexes
+ // in opposite orders, because it'd be too simple otherwise...
+ if (tx.rct_signatures.simple)
{
- if (pubkeys[n].size() != pubkeys[0].size())
- {
- LOG_PRINT_L1("Failed to check ringct signatures: mismatched ring sizes");
- return false;
- }
- }
+ rct::ctkeyM reconstructed_mixRing;
+ std::vector<rct::keyV> reconstructed_II;
- if (tx.rct_signatures.mixRing.empty())
- {
- reconstructed_mixRing.resize(pubkeys[0].size());
- for (size_t n = 0; n < pubkeys.size(); ++n)
+ // if the tx already has a non empty mixRing, use them,
+ // else reconstruct them
+ const rct::ctkeyM &mixRing = tx.rct_signatures.mixRing.empty() ? reconstructed_mixRing : tx.rct_signatures.mixRing;
+ // always do II, because it's split in the simple version
+
+ // all MGs should have the same II size (1)
+ for (size_t n = 0; n < tx.rct_signatures.MGs.size(); ++n)
{
- for (size_t m = 0; m < pubkeys[n].size(); ++m)
+ if (tx.rct_signatures.MGs[n].II.size() != 1)
{
- reconstructed_mixRing[m].push_back(pubkeys[n][m]);
+ LOG_PRINT_L1("Failed to check ringct signatures: mismatched MGs II sizes");
+ return false;
}
}
- }
- if (tx.rct_signatures.MG.II.size() == 1)
- {
reconstructed_II.resize(tx.vin.size());
for (size_t n = 0; n < tx.vin.size(); ++n)
{
- reconstructed_II[n] = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image);
+ reconstructed_II[n].push_back(rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image));
+ reconstructed_II[n].push_back(tx.rct_signatures.MGs[n].II[0]);
}
- 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)
+ if (tx.rct_signatures.mixRing.empty())
{
- LOG_PRINT_L1("Failed to check ringct signatures: mismatched pubkeys/mixRing size");
- return false;
+ reconstructed_mixRing.resize(pubkeys.size());
+ for (size_t n = 0; n < pubkeys.size(); ++n)
+ {
+ for (size_t m = 0; m < pubkeys[n].size(); ++m)
+ {
+ reconstructed_mixRing[n].push_back(pubkeys[n][m]);
+ }
+ }
}
- for (size_t n = 0; n < pubkeys.size(); ++n)
+ // check all this, either recontructed (so should really pass), or not
{
- for (size_t m = 0; m < pubkeys[n].size(); ++m)
+ if (pubkeys.size() != mixRing.size())
{
- if (pubkeys[n][m].dest != rct::rct2pk(mixRing[m][n].dest))
+ LOG_PRINT_L1("Failed to check ringct signatures: mismatched pubkeys/mixRing size");
+ return false;
+ }
+ for (size_t i = 0; i < pubkeys.size(); ++i)
+ {
+ if (pubkeys[i].size() != mixRing[i].size())
{
- LOG_PRINT_L1("Failed to check ringct signatures: mismatched pubkey at vin " << n << ", index " << m);
+ LOG_PRINT_L1("Failed to check ringct signatures: mismatched pubkeys/mixRing size");
return false;
}
- if (pubkeys[n][m].mask != rct::rct2pk(mixRing[m][n].mask))
+ }
+
+ 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[n][m].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[n][m].mask))
+ {
+ LOG_PRINT_L1("Failed to check ringct signatures: mismatched commitment at vin " << n << ", index " << m);
+ return false;
+ }
}
}
}
- }
- if (II.size() != 1 + tx.vin.size())
- {
- LOG_PRINT_L1("Failed to check ringct signatures: mismatched II/vin sizes");
- return false;
+ if (tx.rct_signatures.MGs.size() != tx.vin.size())
+ {
+ LOG_PRINT_L1("Failed to check ringct signatures: mismatched MGs/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, &reconstructed_II[n][0], 32))
+ {
+ LOG_PRINT_L1("Failed to check ringct signatures: mismatched key image");
+ return false;
+ }
+ }
+
+ if (!rct::verRctSimple(tx.rct_signatures, mixRing, &reconstructed_II, rct::hash2rct(tx_prefix_hash)))
+ {
+ LOG_PRINT_L1("Failed to check ringct signatures!");
+ return false;
+ }
}
- for (size_t n = 0; n < tx.vin.size(); ++n)
+ else
{
- if (memcmp(&boost::get<txin_to_key>(tx.vin[n]).k_image, &II[n], 32))
+ 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)
+ {
+ if (pubkeys[n].size() != pubkeys[0].size())
+ {
+ LOG_PRINT_L1("Failed to check ringct signatures: mismatched ring sizes");
+ return false;
+ }
+ }
+
+ if (tx.rct_signatures.mixRing.empty())
+ {
+ 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]);
+ }
+ }
+ }
+
+ if (tx.rct_signatures.MG.II.size() == 1)
+ {
+ reconstructed_II.resize(tx.vin.size());
+ for (size_t n = 0; n < tx.vin.size(); ++n)
+ {
+ 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)
+ {
+ 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 (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;
+ if (!rct::verRct(tx.rct_signatures, mixRing, II, rct::hash2rct(tx_prefix_hash)))
+ {
+ LOG_PRINT_L1("Failed to check ringct signatures!");
+ return false;
+ }
}
}
return true;
diff --git a/src/cryptonote_core/cryptonote_basic.h b/src/cryptonote_core/cryptonote_basic.h
index 91bcef8c5..afe785eb9 100644
--- a/src/cryptonote_core/cryptonote_basic.h
+++ b/src/cryptonote_core/cryptonote_basic.h
@@ -231,11 +231,19 @@ namespace cryptonote
else
{
FIELD(rct_signatures)
- for (size_t i = 0; i < rct_signatures.mixRing.size(); ++i)
+ if (rct_signatures.simple)
{
- if (rct_signatures.mixRing[i].size() != vin.size())
+ if (rct_signatures.mixRing.size() && rct_signatures.mixRing.size() != vin.size())
return false;
}
+ else
+ {
+ for (size_t i = 0; i < rct_signatures.mixRing.size(); ++i)
+ {
+ if (rct_signatures.mixRing[i].size() != vin.size())
+ return false;
+ }
+ }
}
END_SERIALIZE()
diff --git a/src/cryptonote_core/cryptonote_boost_serialization.h b/src/cryptonote_core/cryptonote_boost_serialization.h
index 01239c5ae..35fabe7fb 100644
--- a/src/cryptonote_core/cryptonote_boost_serialization.h
+++ b/src/cryptonote_core/cryptonote_boost_serialization.h
@@ -224,23 +224,16 @@ namespace boost
template <class Archive>
inline void serialize(Archive &a, rct::rctSig &x, const boost::serialization::version_type ver)
{
- a & x.rangeSigs;
- a & x.MG;
- // 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
- }
-
- template <class Archive>
- inline void serialize(Archive &a, rct::sRctSig &x, const boost::serialization::version_type ver)
- {
+ a & x.simple;
// a & x.message; message is not serialized, as it can be reconstructed from the tx data
a & x.rangeSigs;
- a & x.MG;
+ if (x.simple)
+ a & x.MGs;
+ else
+ a & x.MG;
// a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
- a & x.pseudoOuts;
+ if (x.simple)
+ a & x.pseudoOuts;
a & x.ecdhInfo;
a & x.outPk;
a & x.txnFee;
diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp
index 4cc62c165..6578776b4 100644
--- a/src/cryptonote_core/cryptonote_format_utils.cpp
+++ b/src/cryptonote_core/cryptonote_format_utils.cpp
@@ -516,19 +516,6 @@ namespace cryptonote
};
std::vector<input_generation_context_data> in_contexts;
- if (tx.version > 1)
- {
- // ringct requires all real inputs to be at the same index for all inputs // TODO
- BOOST_FOREACH(const tx_source_entry& src_entr, sources)
- {
- if(src_entr.real_output != sources.begin()->real_output)
- {
- LOG_ERROR("All inputs must have the same index for ringct");
- return false;
- }
- }
- }
-
uint64_t summary_inputs_money = 0;
//fill inputs
BOOST_FOREACH(const tx_source_entry& src_entr, sources)
@@ -641,24 +628,46 @@ namespace cryptonote
}
else
{
- // enforce same mixin for all outputs
- size_t n_total_outs = sources[0].outputs.size();
- for (size_t i = 1; i < sources.size(); ++i) {
- if (n_total_outs != sources[i].outputs.size()) {
- LOG_ERROR("Ringct transaction has varying mixin");
- return false;
+ bool all_rct_inputs = true;
+ size_t n_total_outs = sources[0].outputs.size(); // only for non-simple rct
+ BOOST_FOREACH(const tx_source_entry& src_entr, sources)
+ all_rct_inputs &= !(src_entr.mask == rct::identity());
+ bool use_simple_rct = all_rct_inputs;
+
+ if (!use_simple_rct)
+ {
+ // non simple ringct requires all real inputs to be at the same index for all inputs
+ BOOST_FOREACH(const tx_source_entry& src_entr, sources)
+ {
+ if(src_entr.real_output != sources.begin()->real_output)
+ {
+ LOG_ERROR("All inputs must have the same index for non-simple ringct");
+ return false;
+ }
+ }
+
+ // enforce same mixin for all outputs
+ for (size_t i = 1; i < sources.size(); ++i) {
+ if (n_total_outs != sources[i].outputs.size()) {
+ LOG_ERROR("Non-simple ringct transaction has varying mixin");
+ return false;
+ }
}
}
uint64_t amount_in = 0, amount_out = 0;
rct::ctkeyV inSk;
- rct::ctkeyM mixRing(n_total_outs);
+ // mixRing indexing is done the other way round for simple
+ rct::ctkeyM mixRing(use_simple_rct ? sources.size() : n_total_outs);
rct::keyV destinations;
- std::vector<uint64_t> amounts;
+ std::vector<uint64_t> inamounts, outamounts;
+ std::vector<unsigned int> index;
for (size_t i = 0; i < sources.size(); ++i)
{
rct::ctkey ctkey;
amount_in += sources[i].amount;
+ inamounts.push_back(sources[i].amount);
+ index.push_back(sources[i].real_output);
// inSk: (secret key, mask)
ctkey.dest = rct::sk2rct(in_contexts[i].in_ephemeral.sec);
ctkey.mask = sources[i].mask;
@@ -669,21 +678,37 @@ namespace cryptonote
for (size_t i = 0; i < tx.vout.size(); ++i)
{
destinations.push_back(rct::pk2rct(boost::get<txout_to_key>(tx.vout[i].target).key));
- amounts.push_back(tx.vout[i].amount);
+ outamounts.push_back(tx.vout[i].amount);
amount_out += tx.vout[i].amount;
}
- for (size_t i = 0; i < n_total_outs; ++i) // same index assumption
+
+ if (use_simple_rct)
+ {
+ // mixRing indexing is done the other way round for simple
+ for (size_t i = 0; i < sources.size(); ++i)
+ {
+ mixRing[i].resize(sources[i].outputs.size());
+ for (size_t n = 0; n < sources[i].outputs.size(); ++n)
+ {
+ mixRing[i][n] = sources[i].outputs[n].second;
+ }
+ }
+ }
+ else
{
- mixRing[i].resize(sources.size());
- for (size_t n = 0; n < sources.size(); ++n)
+ for (size_t i = 0; i < n_total_outs; ++i) // same index assumption
{
- mixRing[i][n] = sources[n].outputs[i].second;
+ mixRing[i].resize(sources.size());
+ for (size_t n = 0; n < sources.size(); ++n)
+ {
+ mixRing[i][n] = sources[n].outputs[i].second;
+ }
}
}
// fee
- if (amount_in > amount_out)
- amounts.push_back(amount_in - amount_out);
+ if (!use_simple_rct && amount_in > amount_out)
+ outamounts.push_back(amount_in - amount_out);
// zero out all amounts to mask rct outputs, real amounts are now encrypted
for (size_t i = 0; i < tx.vin.size(); ++i)
@@ -696,7 +721,10 @@ namespace cryptonote
crypto::hash tx_prefix_hash;
get_transaction_prefix_hash(tx, tx_prefix_hash);
- tx.rct_signatures = rct::genRct(inSk, destinations, amounts, mixRing, rct::hash2rct(tx_prefix_hash), sources[0].real_output); // same index assumption
+ if (use_simple_rct)
+ tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, index);
+ else
+ tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, sources[0].real_output); // same index assumption
LOG_PRINT2("construct_tx.log", "transaction_created: " << get_transaction_hash(tx) << ENDL << obj_to_json_str(tx) << ENDL, LOG_LEVEL_3);
}