integrate simple rct api

This commit is contained in:
moneromooo-monero 2016-07-10 12:57:22 +01:00
parent 1e8d37e7d8
commit a4d4d6194b
No known key found for this signature in database
GPG key ID: 686F07454D6CEFC3
11 changed files with 400 additions and 188 deletions

View file

@ -2462,95 +2462,193 @@ bool Blockchain::check_tx_inputs(const transaction& tx, tx_verification_context
else else
{ {
// from version 2, check ringct signatures // from version 2, check ringct signatures
rct::ctkeyM reconstructed_mixRing; // obviously, the original and simple rct APIs use a mixRing that's indexes
rct::keyV reconstructed_II; // in opposite orders, because it'd be too simple otherwise...
if (tx.rct_signatures.simple)
// 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()) rct::ctkeyM reconstructed_mixRing;
{ std::vector<rct::keyV> reconstructed_II;
LOG_PRINT_L1("Failed to check ringct signatures: mismatched ring sizes");
return false;
}
}
if (tx.rct_signatures.mixRing.empty()) // if the tx already has a non empty mixRing, use them,
{ // else reconstruct them
reconstructed_mixRing.resize(pubkeys[0].size()); const rct::ctkeyM &mixRing = tx.rct_signatures.mixRing.empty() ? reconstructed_mixRing : tx.rct_signatures.mixRing;
for (size_t n = 0; n < pubkeys.size(); ++n) // 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()); reconstructed_II.resize(tx.vin.size());
for (size_t n = 0; n < tx.vin.size(); ++n) 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)
{
LOG_PRINT_L1("Failed to check ringct signatures: mismatched pubkeys/mixRing size");
return false;
} }
for (size_t n = 0; n < pubkeys.size(); ++n) if (tx.rct_signatures.mixRing.empty())
{ {
for (size_t m = 0; m < pubkeys[n].size(); ++m) reconstructed_mixRing.resize(pubkeys.size());
for (size_t n = 0; n < pubkeys.size(); ++n)
{ {
if (pubkeys[n][m].dest != rct::rct2pk(mixRing[m][n].dest)) for (size_t m = 0; m < pubkeys[n].size(); ++m)
{ {
LOG_PRINT_L1("Failed to check ringct signatures: mismatched pubkey at vin " << n << ", index " << m); reconstructed_mixRing[n].push_back(pubkeys[n][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()) // check all this, either recontructed (so should really pass), or not
{ {
LOG_PRINT_L1("Failed to check ringct signatures: mismatched II/vin sizes"); if (pubkeys.size() != mixRing.size())
return false; {
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 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[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 (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"); LOG_PRINT_L1("Failed to check ringct signatures: mismatched II/vin sizes");
return false; 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))) if (!rct::verRct(tx.rct_signatures, mixRing, II, rct::hash2rct(tx_prefix_hash)))
{ {
LOG_PRINT_L1("Failed to check ringct signatures!"); LOG_PRINT_L1("Failed to check ringct signatures!");
return false; return false;
}
} }
} }
return true; return true;

View file

@ -231,11 +231,19 @@ namespace cryptonote
else else
{ {
FIELD(rct_signatures) 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; 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() END_SERIALIZE()

View file

@ -224,23 +224,16 @@ namespace boost
template <class Archive> template <class Archive>
inline void serialize(Archive &a, rct::rctSig &x, const boost::serialization::version_type ver) inline void serialize(Archive &a, rct::rctSig &x, const boost::serialization::version_type ver)
{ {
a & x.rangeSigs; a & x.simple;
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.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.rangeSigs; 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.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.ecdhInfo;
a & x.outPk; a & x.outPk;
a & x.txnFee; a & x.txnFee;

View file

@ -516,19 +516,6 @@ namespace cryptonote
}; };
std::vector<input_generation_context_data> in_contexts; 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; uint64_t summary_inputs_money = 0;
//fill inputs //fill inputs
BOOST_FOREACH(const tx_source_entry& src_entr, sources) BOOST_FOREACH(const tx_source_entry& src_entr, sources)
@ -641,24 +628,46 @@ namespace cryptonote
} }
else else
{ {
// enforce same mixin for all outputs bool all_rct_inputs = true;
size_t n_total_outs = sources[0].outputs.size(); size_t n_total_outs = sources[0].outputs.size(); // only for non-simple rct
for (size_t i = 1; i < sources.size(); ++i) { BOOST_FOREACH(const tx_source_entry& src_entr, sources)
if (n_total_outs != sources[i].outputs.size()) { all_rct_inputs &= !(src_entr.mask == rct::identity());
LOG_ERROR("Ringct transaction has varying mixin"); bool use_simple_rct = all_rct_inputs;
return false;
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; uint64_t amount_in = 0, amount_out = 0;
rct::ctkeyV inSk; 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; 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) for (size_t i = 0; i < sources.size(); ++i)
{ {
rct::ctkey ctkey; rct::ctkey ctkey;
amount_in += sources[i].amount; amount_in += sources[i].amount;
inamounts.push_back(sources[i].amount);
index.push_back(sources[i].real_output);
// inSk: (secret key, mask) // inSk: (secret key, mask)
ctkey.dest = rct::sk2rct(in_contexts[i].in_ephemeral.sec); ctkey.dest = rct::sk2rct(in_contexts[i].in_ephemeral.sec);
ctkey.mask = sources[i].mask; ctkey.mask = sources[i].mask;
@ -669,21 +678,37 @@ namespace cryptonote
for (size_t i = 0; i < tx.vout.size(); ++i) 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)); 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; amount_out += tx.vout[i].amount;
} }
for (size_t i = 0; i < n_total_outs; ++i) // same index assumption
if (use_simple_rct)
{ {
mixRing[i].resize(sources.size()); // mixRing indexing is done the other way round for simple
for (size_t n = 0; n < sources.size(); ++n) for (size_t i = 0; i < sources.size(); ++i)
{ {
mixRing[i][n] = sources[n].outputs[i].second; 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
{
for (size_t i = 0; i < n_total_outs; ++i) // same index assumption
{
mixRing[i].resize(sources.size());
for (size_t n = 0; n < sources.size(); ++n)
{
mixRing[i][n] = sources[n].outputs[i].second;
}
} }
} }
// fee // fee
if (amount_in > amount_out) if (!use_simple_rct && amount_in > amount_out)
amounts.push_back(amount_in - amount_out); outamounts.push_back(amount_in - amount_out);
// zero out all amounts to mask rct outputs, real amounts are now encrypted // zero out all amounts to mask rct outputs, real amounts are now encrypted
for (size_t i = 0; i < tx.vin.size(); ++i) for (size_t i = 0; i < tx.vin.size(); ++i)
@ -696,7 +721,10 @@ namespace cryptonote
crypto::hash tx_prefix_hash; crypto::hash tx_prefix_hash;
get_transaction_prefix_hash(tx, 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); LOG_PRINT2("construct_tx.log", "transaction_created: " << get_transaction_hash(tx) << ENDL << obj_to_json_str(tx) << ENDL, LOG_LEVEL_3);
} }

View file

@ -329,7 +329,7 @@ namespace rct {
// this shows that sum inputs = sum outputs // this shows that sum inputs = sum outputs
//Ver: //Ver:
// verifies the above sig is created corretly // verifies the above sig is created corretly
mgSig proveRctMG(const ctkeyM & pubs, const ctkeyV & inSk, const ctkeyV &outSk, const ctkeyV & outPk, unsigned int index, key txnFeeKey, const key &base_hash) { mgSig proveRctMG(const key &message, const ctkeyM & pubs, const ctkeyV & inSk, const ctkeyV &outSk, const ctkeyV & outPk, unsigned int index, key txnFeeKey) {
mgSig mg; mgSig mg;
//setup vars //setup vars
size_t cols = pubs.size(); size_t cols = pubs.size();
@ -374,9 +374,9 @@ namespace rct {
sc_sub(sk[rows].bytes, sk[rows].bytes, outSk[j].mask.bytes); //subtract output masks in last row.. sc_sub(sk[rows].bytes, sk[rows].bytes, outSk[j].mask.bytes); //subtract output masks in last row..
} }
ctkeyV signed_data = outPk; ctkeyV signed_data = outPk;
signed_data.push_back(ctkey({base_hash, identity()})); signed_data.push_back(ctkey({message, identity()}));
key message = cn_fast_hash(signed_data); key msg = cn_fast_hash(signed_data);
return MLSAG_Gen(message, M, sk, index); return MLSAG_Gen(msg, M, sk, index);
} }
@ -415,7 +415,7 @@ namespace rct {
// this shows that sum inputs = sum outputs // this shows that sum inputs = sum outputs
//Ver: //Ver:
// verifies the above sig is created corretly // verifies the above sig is created corretly
bool verRctMG(mgSig mg, const keyV &II, const ctkeyM & pubs, const ctkeyV & outPk, key txnFeeKey, const key &base_hash) { bool verRctMG(mgSig mg, const keyV &II, const ctkeyM & pubs, const ctkeyV & outPk, key txnFeeKey, const key &message) {
//setup vars //setup vars
size_t cols = pubs.size(); size_t cols = pubs.size();
CHECK_AND_ASSERT_MES(cols >= 1, false, "Empty pubs"); CHECK_AND_ASSERT_MES(cols >= 1, false, "Empty pubs");
@ -447,11 +447,11 @@ namespace rct {
subKeys(M[i][rows], M[i][rows], txnFeeKey); subKeys(M[i][rows], M[i][rows], txnFeeKey);
} }
ctkeyV signed_data = outPk; ctkeyV signed_data = outPk;
signed_data.push_back(ctkey({base_hash, identity()})); signed_data.push_back(ctkey({message, identity()}));
key message = cn_fast_hash(signed_data); key msg = cn_fast_hash(signed_data);
DP("message:"); DP("message:");
DP(message); DP(msg);
return MLSAG_Ver(message, M, mg, II); return MLSAG_Ver(msg, M, mg, II);
} }
//Ring-ct Simple MG sigs //Ring-ct Simple MG sigs
@ -535,7 +535,7 @@ 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
// 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 ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> amounts, const ctkeyM &mixRing, const key &base_hash, unsigned int index) { rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & amounts, const ctkeyM &mixRing, unsigned int index) {
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(index < mixRing.size(), "Bad index into mixRing"); CHECK_AND_ASSERT_THROW_MES(index < mixRing.size(), "Bad index into mixRing");
for (size_t n = 0; n < mixRing.size(); ++n) { for (size_t n = 0; n < mixRing.size(); ++n) {
@ -543,6 +543,7 @@ namespace rct {
} }
rctSig rv; rctSig rv;
rv.simple = false;
rv.outPk.resize(destinations.size()); rv.outPk.resize(destinations.size());
rv.rangeSigs.resize(destinations.size()); rv.rangeSigs.resize(destinations.size());
rv.ecdhInfo.resize(destinations.size()); rv.ecdhInfo.resize(destinations.size());
@ -578,23 +579,22 @@ namespace rct {
key txnFeeKey = scalarmultH(d2h(rv.txnFee)); key txnFeeKey = scalarmultH(d2h(rv.txnFee));
rv.mixRing = mixRing; rv.mixRing = mixRing;
rv.base_hash = base_hash; rv.message = message;
rv.MG = proveRctMG(rv.mixRing, inSk, outSk, rv.outPk, index, txnFeeKey, base_hash); rv.MG = proveRctMG(message, rv.mixRing, inSk, outSk, rv.outPk, index, txnFeeKey);
return rv; return rv;
} }
rctSig genRct(const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> amounts, const key &base_hash, const int mixin) { rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & amounts, const int mixin) {
unsigned int index; unsigned int index;
ctkeyM mixRing; ctkeyM mixRing;
tie(mixRing, index) = populateFromBlockchain(inPk, mixin); tie(mixRing, index) = populateFromBlockchain(inPk, mixin);
return genRct(inSk, destinations, amounts, mixRing, base_hash, index); return genRct(message, inSk, destinations, amounts, mixRing, index);
} }
//RCT simple //RCT simple
//for post-rct only //for post-rct only
sRctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const std::vector<unsigned int> & index) { rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const std::vector<unsigned int> & index) {
CHECK_AND_ASSERT_THROW_MES(inamounts.size() > 0, "Empty inamounts"); CHECK_AND_ASSERT_THROW_MES(inamounts.size() > 0, "Empty inamounts");
CHECK_AND_ASSERT_THROW_MES(inPk.size() == inSk.size(), "Different number of inPk/inSk");
CHECK_AND_ASSERT_THROW_MES(inamounts.size() == inSk.size(), "Different number of inamounts/inSk"); 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(outamounts.size() == destinations.size(), "Different number of amounts/destinations");
CHECK_AND_ASSERT_THROW_MES(index.size() == inSk.size(), "Different number of index/inSk"); CHECK_AND_ASSERT_THROW_MES(index.size() == inSk.size(), "Different number of index/inSk");
@ -603,7 +603,8 @@ namespace rct {
CHECK_AND_ASSERT_THROW_MES(index[n] < mixRing[n].size(), "Bad index into mixRing"); CHECK_AND_ASSERT_THROW_MES(index[n] < mixRing[n].size(), "Bad index into mixRing");
} }
sRctSig rv; rctSig rv;
rv.simple = true;
rv.message = message; rv.message = message;
rv.outPk.resize(destinations.size()); rv.outPk.resize(destinations.size());
rv.rangeSigs.resize(destinations.size()); rv.rangeSigs.resize(destinations.size());
@ -637,24 +638,24 @@ namespace rct {
// key txnFeeKey = scalarmultH(d2h(rv.txnFee)); // key txnFeeKey = scalarmultH(d2h(rv.txnFee));
rv.mixRing = mixRing; rv.mixRing = mixRing;
rv.pseudoOuts.resize(inamounts.size()); rv.pseudoOuts.resize(inamounts.size());
rv.MG.resize(inamounts.size()); rv.MGs.resize(inamounts.size());
key sumpouts = zero(); //sum pseudoOut masks key sumpouts = zero(); //sum pseudoOut masks
key a; key a;
for (i = 0 ; i < inamounts.size() - 1; i++) { for (i = 0 ; i < inamounts.size() - 1; i++) {
skGen(a); skGen(a);
sc_add(sumpouts.bytes, a.bytes, sumpouts.bytes); sc_add(sumpouts.bytes, a.bytes, sumpouts.bytes);
genC(rv.pseudoOuts[i], a, inamounts[i]); genC(rv.pseudoOuts[i], a, inamounts[i]);
rv.MG[i] = proveRctMGSimple(message, rv.mixRing[i], inSk[i], a, rv.pseudoOuts[i], index[i]); rv.MGs[i] = proveRctMGSimple(message, rv.mixRing[i], inSk[i], a, rv.pseudoOuts[i], index[i]);
} }
rv.mixRing = mixRing; rv.mixRing = mixRing;
sc_sub(a.bytes, sumout.bytes, sumpouts.bytes); sc_sub(a.bytes, sumout.bytes, sumpouts.bytes);
genC(rv.pseudoOuts[i], a, inamounts[i]); genC(rv.pseudoOuts[i], a, inamounts[i]);
DP(rv.pseudoOuts[i]); DP(rv.pseudoOuts[i]);
rv.MG[i] = proveRctMGSimple(message, rv.mixRing[i], inSk[i], a, rv.pseudoOuts[i], index[i]); rv.MGs[i] = proveRctMGSimple(message, rv.mixRing[i], inSk[i], a, rv.pseudoOuts[i], index[i]);
return rv; return rv;
} }
sRctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, xmr_amount txnFee, unsigned int mixin) { rctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, xmr_amount txnFee, unsigned int mixin) {
std::vector<unsigned int> index; std::vector<unsigned int> index;
index.resize(inPk.size()); index.resize(inPk.size());
ctkeyM mixRing; ctkeyM mixRing;
@ -663,7 +664,7 @@ namespace rct {
mixRing[i].resize(mixin+1); mixRing[i].resize(mixin+1);
index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin); index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin);
} }
return genRctSimple(message, inSk, inPk, destinations, inamounts, outamounts, txnFee, mixRing, index); return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, index);
} }
//RingCT protocol //RingCT protocol
@ -676,7 +677,8 @@ namespace rct {
//decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1) //decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1)
// 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
bool verRct(const rctSig & rv, const ctkeyM &mixRing, const keyV &II, const key &base_hash) { bool verRct(const rctSig & rv, const ctkeyM &mixRing, const keyV &II, const key &message) {
CHECK_AND_ASSERT_MES(!rv.simple, false, "verRct called on simple rctSig");
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.rangeSigs.size(), false, "Mismatched sizes of rv.outPk and rv.rangeSigs"); CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.rangeSigs.size(), false, "Mismatched sizes of rv.outPk and rv.rangeSigs");
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of rv.outPk and rv.ecdhInfo"); CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of rv.outPk and rv.ecdhInfo");
@ -694,7 +696,7 @@ namespace rct {
} }
//compute txn fee //compute txn fee
key txnFeeKey = scalarmultH(d2h(rv.txnFee)); key txnFeeKey = scalarmultH(d2h(rv.txnFee));
bool mgVerd = verRctMG(rv.MG, II, mixRing, rv.outPk, txnFeeKey, base_hash); bool mgVerd = verRctMG(rv.MG, II, mixRing, rv.outPk, txnFeeKey, message);
DP("mg sig verified?"); DP("mg sig verified?");
DP(mgVerd); DP(mgVerd);
@ -706,19 +708,28 @@ namespace rct {
} }
} }
bool verRct(const rctSig & rv) { bool verRct(const rctSig & rv) {
return verRct(rv, rv.mixRing, rv.MG.II, rv.base_hash); return verRct(rv, rv.mixRing, rv.MG.II, rv.message);
} }
//ver RingCT simple //ver RingCT simple
//assumes only post-rct style inputs (at least for max anonymity) //assumes only post-rct style inputs (at least for max anonymity)
bool verRctSimple(const sRctSig & rv) { bool verRctSimple(const rctSig & rv, const ctkeyM &mixRing, const std::vector<keyV> *II, const key &message) {
size_t i = 0; size_t i = 0;
bool rvb = true; bool rvb = true;
CHECK_AND_ASSERT_MES(rv.simple, false, "verRctSimple called on non simple rctSig");
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.rangeSigs.size(), false, "Mismatched sizes of rv.outPk and rv.rangeSigs"); CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.rangeSigs.size(), false, "Mismatched sizes of rv.outPk and rv.rangeSigs");
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of rv.outPk and rv.ecdhInfo"); CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of rv.outPk and rv.ecdhInfo");
CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.MGs.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.MGs"); CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.MGs.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.MGs");
CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.MGs"); CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == mixRing.size(), false, "Mismatched sizes of rv.pseudoOuts and mixRing");
CHECK_AND_ASSERT_MES(!II || II->size() == mixRing.size(), false, "Mismatched II/mixRing size");
if (II)
{
for (size_t n = 0; n < II->size(); ++n)
{
CHECK_AND_ASSERT_MES((*II)[n].size() == 2, false, "Bad II size");
}
}
key sumOutpks = identity(); key sumOutpks = identity();
for (i = 0; i < rv.outPk.size(); i++) { for (i = 0; i < rv.outPk.size(); i++) {
@ -733,8 +744,8 @@ namespace rct {
bool tmpb = false; bool tmpb = false;
key sumPseudoOuts = identity(); key sumPseudoOuts = identity();
for (i = 0 ; i < rv.mixRing.size() ; i++) { for (i = 0 ; i < mixRing.size() ; i++) {
tmpb = verRctMGSimple(rv.message, rv.MG[i], rv.MG[i].II, rv.mixRing[i], rv.pseudoOuts[i]); tmpb = verRctMGSimple(message, rv.MGs[i], II ? (*II)[i] : rv.MGs[i].II, mixRing[i], rv.pseudoOuts[i]);
addKeys(sumPseudoOuts, sumPseudoOuts, rv.pseudoOuts[i]); addKeys(sumPseudoOuts, sumPseudoOuts, rv.pseudoOuts[i]);
DP(tmpb); DP(tmpb);
if (!tmpb) { if (!tmpb) {
@ -755,6 +766,10 @@ namespace rct {
return (rvb && mgVerd); return (rvb && mgVerd);
} }
bool verRctSimple(const rctSig & rv) {
return verRctSimple(rv, rv.mixRing, NULL, rv.message);
}
//RingCT protocol //RingCT protocol
//genRct: //genRct:
// creates an rctSig with all data necessary to verify the rangeProofs and that the signer owns one of the // creates an rctSig with all data necessary to verify the rangeProofs and that the signer owns one of the
@ -766,6 +781,7 @@ 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) { xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask) {
CHECK_AND_ASSERT_MES(!rv.simple, false, "decodeRct called on simple rctSig");
CHECK_AND_ASSERT_THROW_MES(rv.rangeSigs.size() > 0, "Empty rv.rangeSigs"); CHECK_AND_ASSERT_THROW_MES(rv.rangeSigs.size() > 0, "Empty rv.rangeSigs");
CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.rangeSigs.size(), "Mismatched sizes of rv.outPk and rv.rangeSigs"); CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.rangeSigs.size(), "Mismatched sizes of rv.outPk and rv.rangeSigs");
CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index"); CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index");
@ -793,7 +809,8 @@ namespace rct {
return decodeRct(rv, sk, i, mask); return decodeRct(rv, sk, i, mask);
} }
xmr_amount decodeRct(const sRctSig & rv, const key & sk, unsigned int i) { xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask) {
CHECK_AND_ASSERT_MES(rv.simple, false, "decodeRct called on non simple rctSig");
CHECK_AND_ASSERT_THROW_MES(rv.rangeSigs.size() > 0, "Empty rv.rangeSigs"); CHECK_AND_ASSERT_THROW_MES(rv.rangeSigs.size() > 0, "Empty rv.rangeSigs");
CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.rangeSigs.size(), "Mismatched sizes of rv.outPk and rv.rangeSigs"); CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.rangeSigs.size(), "Mismatched sizes of rv.outPk and rv.rangeSigs");
CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index"); CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index");
@ -801,7 +818,7 @@ namespace rct {
//mask amount and mask //mask amount and mask
ecdhTuple ecdh_info = rv.ecdhInfo[i]; ecdhTuple ecdh_info = rv.ecdhInfo[i];
ecdhDecode(ecdh_info, sk); ecdhDecode(ecdh_info, sk);
key 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;
DP("C"); DP("C");
@ -815,4 +832,9 @@ namespace rct {
} }
return h2d(amount); return h2d(amount);
} }
xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i) {
key mask;
return decodeRctSimple(rv, sk, i, mask);
}
} }

View file

@ -112,9 +112,9 @@ namespace rct {
// this shows that sum inputs = sum outputs // this shows that sum inputs = sum outputs
//Ver: //Ver:
// verifies the above sig is created corretly // verifies the above sig is created corretly
mgSig proveRctMG(const ctkeyM & pubs, const ctkeyV & inSk, const keyV &outMasks, const ctkeyV & outPk, unsigned int index, key txnFee, const key &base_hash); mgSig proveRctMG(const ctkeyM & pubs, const ctkeyV & inSk, const keyV &outMasks, const ctkeyV & outPk, unsigned int index, key txnFee, const key &message);
mgSig proveRctMGSimple(const key & message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, unsigned int index); mgSig proveRctMGSimple(const key & message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, unsigned int index);
bool verRctMG(mgSig mg, const ctkeyM & pubs, const ctkeyV & outPk, key txnFee, const key &base_hash); bool verRctMG(mgSig mg, const ctkeyM & pubs, const ctkeyV & outPk, key txnFee, const key &message);
bool verRctMGSimple(const key &message, const mgSig &mg, const keyV &II, const ctkeyV & pubs, const key & C); bool verRctMGSimple(const key &message, const mgSig &mg, const keyV &II, const ctkeyV & pubs, const key & C);
//These functions get keys from blockchain //These functions get keys from blockchain
@ -135,16 +135,18 @@ namespace rct {
//decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1) //decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1)
// 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
rctSig genRct(const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> amounts, const ctkeyM &mixRing, const key &bash_hash, unsigned int index); rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & amounts, const ctkeyM &mixRing, unsigned int index);
rctSig genRct(const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> amounts, const key &bash_hash, const int mixin); rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & amounts, const int mixin);
sRctSig genRctSimple(const key & message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & inamounts, const vector<xmr_amount> & outamounts, xmr_amount txnFee, unsigned int mixin); rctSig genRctSimple(const key & message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & inamounts, const vector<xmr_amount> & outamounts, xmr_amount txnFee, unsigned int mixin);
sRctSig genRctSimple(const key & message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & inamounts, const vector<xmr_amount> & outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const std::vector<unsigned int> & index); rctSig genRctSimple(const key & message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & inamounts, const vector<xmr_amount> & outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const std::vector<unsigned int> & index);
bool verRct(const rctSig & rv); bool verRct(const rctSig & rv);
bool verRct(const rctSig & rv, const ctkeyM &mixRing, const keyV &II, const key &base_hash); bool verRct(const rctSig & rv, const ctkeyM &mixRing, const keyV &II, const key &message);
bool verRctSimple(const sRctSig & rv); bool verRctSimple(const rctSig & rv);
bool verRctSimple(const rctSig & rv, const ctkeyM &mixRing, const std::vector<keyV> *II, const key &message);
xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask); xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask);
xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i); xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i);
xmr_amount decodeRct(const sRctSig & rv, const key & sk, unsigned int i); xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i);
xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key & mask);
} }
#endif /* RCTSIGS_H */ #endif /* RCTSIGS_H */

View file

@ -183,44 +183,29 @@ namespace rct {
// outPk contains public keypairs which are destinations (P, C), // outPk contains public keypairs which are destinations (P, C),
// P = address, C = commitment to amount // P = address, C = commitment to amount
struct rctSig { struct rctSig {
vector<rangeSig> rangeSigs; bool simple;
mgSig MG;
ctkeyM mixRing; //the set of all pubkeys / copy
//pairs that you mix with
vector<ecdhTuple> ecdhInfo;
ctkeyV outPk;
xmr_amount txnFee;
key base_hash;
BEGIN_SERIALIZE_OBJECT()
FIELD(rangeSigs)
FIELD(MG)
// FIELD(mixRing) - not serialized, it can be reconstructed
FIELD(ecdhInfo)
FIELD(outPk)
FIELD(txnFee)
// FIELD(base_hash) - not serialized, it can be reconstructed
END_SERIALIZE()
};
//rct simple variant
struct sRctSig {
key message; key message;
vector<rangeSig> rangeSigs; vector<rangeSig> rangeSigs;
vector<mgSig> MG; mgSig MG; // for non simple rct
vector<ctkeyV> mixRing; //the set of all pubkeys / copy vector<mgSig> MGs; // for simple rct
ctkeyM mixRing; //the set of all pubkeys / copy
//pairs that you mix with //pairs that you mix with
keyV pseudoOuts; //C keyV pseudoOuts; //C - for simple rct
vector<ecdhTuple> ecdhInfo; vector<ecdhTuple> ecdhInfo;
ctkeyV outPk; ctkeyV outPk;
xmr_amount txnFee; // contains b xmr_amount txnFee; // contains b
BEGIN_SERIALIZE_OBJECT() BEGIN_SERIALIZE_OBJECT()
FIELD(simple)
// FIELD(message) - not serialized, it can be reconstructed // FIELD(message) - not serialized, it can be reconstructed
FIELD(rangeSigs) FIELD(rangeSigs)
FIELD(MG) if (simple)
FIELD(MGs)
else
FIELD(MG)
// FIELD(mixRing) - not serialized, it can be reconstructed // FIELD(mixRing) - not serialized, it can be reconstructed
FIELD(pseudoOuts) if (simple)
FIELD(pseudoOuts)
FIELD(ecdhInfo) FIELD(ecdhInfo)
FIELD(outPk) FIELD(outPk)
FIELD(txnFee) FIELD(txnFee)

View file

@ -193,6 +193,14 @@ void wallet2::check_acc_out(const account_keys &acc, const tx_out &o, const cryp
error = false; error = false;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
static uint64_t decodeRct(const rct::rctSig & rv, const rct::key & sk, unsigned int i, rct::key & mask)
{
if (rv.simple)
return rct::decodeRctSimple(rv, sk, i, mask);
else
return rct::decodeRct(rv, sk, i, mask);
}
//----------------------------------------------------------------------------------------------------
void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_t height, uint64_t ts, bool miner_tx, bool pool) void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_t height, uint64_t ts, bool miner_tx, bool pool)
{ {
if (!miner_tx) if (!miner_tx)
@ -251,7 +259,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_
outs.push_back(0); outs.push_back(0);
if (money_transfered == 0) if (money_transfered == 0)
money_transfered = rct::decodeRct(tx.rct_signatures, rct::sk2rct(in_ephemeral[0].sec), 0, mask[0]); money_transfered = tools::decodeRct(tx.rct_signatures, rct::sk2rct(in_ephemeral[0].sec), 0, mask[0]);
amount[0] = money_transfered; amount[0] = money_transfered;
tx_money_got_in_outs = money_transfered; tx_money_got_in_outs = money_transfered;
@ -290,7 +298,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_
outs.push_back(i); outs.push_back(i);
if (money_transfered[i] == 0) if (money_transfered[i] == 0)
money_transfered[i] = rct::decodeRct(tx.rct_signatures, rct::sk2rct(in_ephemeral[i].sec), i, mask[i]); money_transfered[i] = tools::decodeRct(tx.rct_signatures, rct::sk2rct(in_ephemeral[i].sec), i, mask[i]);
tx_money_got_in_outs += money_transfered[i]; tx_money_got_in_outs += money_transfered[i];
amount[i] = money_transfered[i]; amount[i] = money_transfered[i];
} }
@ -334,7 +342,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_
outs.push_back(i); outs.push_back(i);
if (money_transfered[i] == 0) if (money_transfered[i] == 0)
money_transfered[i] = rct::decodeRct(tx.rct_signatures, rct::sk2rct(in_ephemeral[i].sec), i, mask[i]); money_transfered[i] = tools::decodeRct(tx.rct_signatures, rct::sk2rct(in_ephemeral[i].sec), i, mask[i]);
tx_money_got_in_outs += money_transfered[i]; tx_money_got_in_outs += money_transfered[i];
amount[i] = money_transfered[i]; amount[i] = money_transfered[i];
} }
@ -362,7 +370,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_
outs.push_back(i); outs.push_back(i);
if (money_transfered == 0) if (money_transfered == 0)
money_transfered = rct::decodeRct(tx.rct_signatures, rct::sk2rct(in_ephemeral[i].sec), i, mask[i]); money_transfered = tools::decodeRct(tx.rct_signatures, rct::sk2rct(in_ephemeral[i].sec), i, mask[i]);
amount[i] = money_transfered; amount[i] = money_transfered;
tx_money_got_in_outs += money_transfered; tx_money_got_in_outs += money_transfered;
} }
@ -3008,19 +3016,29 @@ static size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs)
// rct signatures // rct signatures
// simple
size += 1;
// message
size += 32;
// rangeSigs // rangeSigs
size += (2*64*32+32+64*32) * n_outputs; size += (2*64*32+32+64*32) * n_outputs;
// MG - only the last slot of II is saved, the rest can be reconstructed // MGs - only the last slot of II is saved, the rest can be reconstructed
size += 32 * (mixin+1) * n_inputs + 32 + 32 * (/*n_inputs+*/1) ; size += n_inputs * (32 * (mixin+1) * n_inputs + 32 + 32 * (/*n_inputs+*/1));
// mixRing - not serialized, can be reconstructed // mixRing - not serialized, can be reconstructed
/* size += 2 * 32 * (mixin+1) * n_inputs; */ /* size += 2 * 32 * (mixin+1) * n_inputs; */
// pseudoOuts
size += 32 * n_outputs;
// ecdhInfo // ecdhInfo
size += 3 * 32 * n_outputs; size += 3 * 32 * n_outputs;
// outPk // outPk
size += 2 * 32 * n_outputs; size += 2 * 32 * n_outputs;
// txnFee
size += 4;
LOG_PRINT_L2("estimated rct tx size for " << n_inputs << " at mixin " << mixin << " and " << n_outputs << ": " << size << " (" << (32 * n_inputs + 2 * 32 * (mixin+1) * n_inputs) << " saved)"); LOG_PRINT_L2("estimated rct tx size for " << n_inputs << " at mixin " << mixin << " and " << n_outputs << ": " << size << " (" << (32 * n_inputs + 2 * 32 * (mixin+1) * n_inputs) << " saved)");
return size; return size;

View file

@ -127,7 +127,10 @@ bool gen_rct_tx_validation_base::generate_with(std::vector<test_event_entry>& ev
cryptonote::keypair in_ephemeral; cryptonote::keypair in_ephemeral;
crypto::key_image ki; crypto::key_image ki;
cryptonote::generate_key_image_helper(miner_accounts[n].get_keys(), tx_pub_key, o, in_ephemeral, ki); cryptonote::generate_key_image_helper(miner_accounts[n].get_keys(), tx_pub_key, o, in_ephemeral, ki);
rct::decodeRct(rct_txes[n].rct_signatures, rct::sk2rct(in_ephemeral.sec), o, rct_tx_masks[o+n*4]); if (rct_txes[n].rct_signatures.simple)
rct::decodeRctSimple(rct_txes[n].rct_signatures, rct::sk2rct(in_ephemeral.sec), o, rct_tx_masks[o+n*4]);
else
rct::decodeRct(rct_txes[n].rct_signatures, rct::sk2rct(in_ephemeral.sec), o, rct_tx_masks[o+n*4]);
} }
CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk_txes[n], blk_last, miner_account, CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk_txes[n], blk_last, miner_account,

View file

@ -187,7 +187,7 @@ TEST(ringct, range_proofs)
destinations.push_back(Pk); destinations.push_back(Pk);
//compute rct data with mixin 500 //compute rct data with mixin 500
rctSig s = genRct(sc, pc, destinations, amounts, rct::zero(), 3); rctSig s = genRct(rct::zero(), sc, pc, destinations, amounts, 3);
//verify rct data //verify rct data
ASSERT_TRUE(verRct(s)); ASSERT_TRUE(verRct(s));
@ -204,7 +204,7 @@ TEST(ringct, range_proofs)
//compute rct data with mixin 500 //compute rct data with mixin 500
s = genRct(sc, pc, destinations, amounts, rct::zero(), 3); s = genRct(rct::zero(), sc, pc, destinations, amounts, 3);
//verify rct data //verify rct data
ASSERT_FALSE(verRct(s)); ASSERT_FALSE(verRct(s));
@ -248,7 +248,7 @@ TEST(ringct, range_proofs_with_fee)
destinations.push_back(Pk); destinations.push_back(Pk);
//compute rct data with mixin 500 //compute rct data with mixin 500
rctSig s = genRct(sc, pc, destinations, amounts, rct::zero(), 3); rctSig s = genRct(rct::zero(), sc, pc, destinations, amounts, 3);
//verify rct data //verify rct data
ASSERT_TRUE(verRct(s)); ASSERT_TRUE(verRct(s));
@ -265,7 +265,7 @@ TEST(ringct, range_proofs_with_fee)
//compute rct data with mixin 500 //compute rct data with mixin 500
s = genRct(sc, pc, destinations, amounts, rct::zero(), 3); s = genRct(rct::zero(), sc, pc, destinations, amounts, 3);
//verify rct data //verify rct data
ASSERT_FALSE(verRct(s)); ASSERT_FALSE(verRct(s));
@ -274,6 +274,60 @@ TEST(ringct, range_proofs_with_fee)
ASSERT_TRUE(decodeRct(s, Sk, 1)); ASSERT_TRUE(decodeRct(s, Sk, 1));
} }
TEST(ringct, simple)
{
ctkeyV sc, pc;
ctkey sctmp, pctmp;
//this vector corresponds to output amounts
vector<xmr_amount>outamounts;
//this vector corresponds to input amounts
vector<xmr_amount>inamounts;
//this keyV corresponds to destination pubkeys
keyV destinations;
//add fake input 3000
//the sc is secret data
//pc is public data
tie(sctmp, pctmp) = ctskpkGen(3000);
sc.push_back(sctmp);
pc.push_back(pctmp);
inamounts.push_back(3000);
//add fake input 3000
//the sc is secret data
//pc is public data
tie(sctmp, pctmp) = ctskpkGen(3000);
sc.push_back(sctmp);
pc.push_back(pctmp);
inamounts.push_back(3000);
//add output 5000
outamounts.push_back(5000);
//add the corresponding destination pubkey
key Sk, Pk;
skpkGen(Sk, Pk);
destinations.push_back(Pk);
//add output 999
outamounts.push_back(999);
//add the corresponding destination pubkey
skpkGen(Sk, Pk);
destinations.push_back(Pk);
key message = skGen(); //real message later (hash of txn..)
//compute sig with mixin 2
xmr_amount txnfee = 1;
rctSig s = genRctSimple(message, sc, pc, destinations,inamounts, outamounts, txnfee, 2);
//verify ring ct signature
ASSERT_TRUE(verRctSimple(s));
//decode received amount corresponding to output pubkey index 1
ASSERT_TRUE(decodeRctSimple(s, Sk, 1));
}
static rct::rctSig make_sample_rct_sig(int n_inputs, const uint64_t input_amounts[], int n_outputs, const uint64_t output_amounts[], bool last_is_fee) static rct::rctSig make_sample_rct_sig(int n_inputs, const uint64_t input_amounts[], int n_outputs, const uint64_t output_amounts[], bool last_is_fee)
{ {
ctkeyV sc, pc; ctkeyV sc, pc;
@ -295,7 +349,7 @@ static rct::rctSig make_sample_rct_sig(int n_inputs, const uint64_t input_amount
destinations.push_back(Pk); destinations.push_back(Pk);
} }
return genRct(sc, pc, destinations, amounts, rct::zero(), 3);; return genRct(rct::zero(), sc, pc, destinations, amounts, 3);;
} }
static bool range_proof_test(bool expected_valid, static bool range_proof_test(bool expected_valid,

View file

@ -565,7 +565,7 @@ TEST(Serialization, serializes_ringct_types)
rct::skpkGen(Sk, Pk); rct::skpkGen(Sk, Pk);
destinations.push_back(Pk); destinations.push_back(Pk);
//compute rct data with mixin 500 //compute rct data with mixin 500
s0 = rct::genRct(sc, pc, destinations, amounts, rct::zero(), 3); s0 = rct::genRct(rct::zero(), sc, pc, destinations, amounts, 3);
mg0 = s0.MG; mg0 = s0.MG;
ASSERT_TRUE(serialization::dump_binary(mg0, blob)); ASSERT_TRUE(serialization::dump_binary(mg0, blob));
@ -588,6 +588,7 @@ TEST(Serialization, serializes_ringct_types)
ASSERT_TRUE(serialization::dump_binary(s0, blob)); ASSERT_TRUE(serialization::dump_binary(s0, blob));
ASSERT_TRUE(serialization::parse_binary(blob, s1)); ASSERT_TRUE(serialization::parse_binary(blob, s1));
ASSERT_TRUE(s0.simple == s1.simple);
ASSERT_TRUE(s0.rangeSigs.size() == s1.rangeSigs.size()); ASSERT_TRUE(s0.rangeSigs.size() == s1.rangeSigs.size());
for (size_t n = 0; n < s0.rangeSigs.size(); ++n) for (size_t n = 0; n < s0.rangeSigs.size(); ++n)
{ {