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.
This commit is contained in:
parent
106e3dc3d4
commit
20e50ec7f7
|
@ -2461,6 +2461,13 @@ 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;
|
||||||
|
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
|
// RCT needs the same mixin for all inputs
|
||||||
for (size_t n = 1; n < pubkeys.size(); ++n)
|
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;
|
if (tx.rct_signatures.mixRing.empty())
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
LOG_PRINT_L1("Failed to check ringct signatures: mismatched pubkeys/mixRing size");
|
reconstructed_mixRing.resize(pubkeys[0].size());
|
||||||
return false;
|
for (size_t n = 0; n < pubkeys.size(); ++n)
|
||||||
}
|
|
||||||
|
|
||||||
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(tx.rct_signatures.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[m].push_back(pubkeys[n][m]);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (pubkeys[n][m].mask != rct::rct2pk(tx.rct_signatures.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 (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!");
|
LOG_PRINT_L1("Failed to check ringct signatures!");
|
||||||
return false;
|
return false;
|
||||||
|
@ -2613,7 +2659,8 @@ bool Blockchain::check_tx_input(size_t tx_version, const txin_to_key& txin, cons
|
||||||
}
|
}
|
||||||
else
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,8 @@
|
||||||
#include <boost/serialization/map.hpp>
|
#include <boost/serialization/map.hpp>
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
#include <boost/serialization/is_bitwise_serializable.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 "cryptonote_basic.h"
|
||||||
#include "common/unordered_containers_boost_serialization.h"
|
#include "common/unordered_containers_boost_serialization.h"
|
||||||
#include "crypto/crypto.h"
|
#include "crypto/crypto.h"
|
||||||
|
@ -196,12 +198,19 @@ namespace boost
|
||||||
a & x.s;
|
a & x.s;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Archive>
|
inline void serialize(boost::archive::binary_iarchive &a, rct::mgSig &x, const boost::serialization::version_type ver)
|
||||||
inline void serialize(Archive &a, rct::mgSig &x, const boost::serialization::version_type ver)
|
|
||||||
{
|
{
|
||||||
a & x.ss;
|
a & x.ss;
|
||||||
a & x.cc;
|
a & x.cc;
|
||||||
a & x.II;
|
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.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
|
@ -217,10 +226,11 @@ namespace boost
|
||||||
{
|
{
|
||||||
a & x.rangeSigs;
|
a & x.rangeSigs;
|
||||||
a & x.MG;
|
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.ecdhInfo;
|
||||||
a & x.outPk;
|
a & x.outPk;
|
||||||
a & x.txnFee;
|
a & x.txnFee;
|
||||||
|
// a & x.bash_hash; bash_hash is not serialized, as it can be reconstructed from the tx data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -226,7 +226,7 @@ namespace rct {
|
||||||
// Gen creates a signature which proves that for some column in the keymatrix "pk"
|
// Gen creates a signature which proves that for some column in the keymatrix "pk"
|
||||||
// the signer knows a secret key for each row in that column
|
// the signer knows a secret key for each row in that column
|
||||||
// Ver verifies that the MG sig was created correctly
|
// Ver verifies that the MG sig was created correctly
|
||||||
bool MLSAG_Ver(key message, const keyM & pk, const mgSig & rv) {
|
bool MLSAG_Ver(key message, const keyM & pk, const mgSig & rv, const keyV &II) {
|
||||||
|
|
||||||
size_t cols = pk.size();
|
size_t cols = pk.size();
|
||||||
CHECK_AND_ASSERT_MES(cols >= 2, false, "Error! What is c if cols = 1!");
|
CHECK_AND_ASSERT_MES(cols >= 2, false, "Error! What is c if cols = 1!");
|
||||||
|
@ -235,7 +235,7 @@ namespace rct {
|
||||||
for (size_t i = 1; i < cols; ++i) {
|
for (size_t i = 1; i < cols; ++i) {
|
||||||
CHECK_AND_ASSERT_MES(pk[i].size() == rows, false, "pk is not rectangular");
|
CHECK_AND_ASSERT_MES(pk[i].size() == rows, false, "pk is not rectangular");
|
||||||
}
|
}
|
||||||
CHECK_AND_ASSERT_MES(rv.II.size() == rows, false, "Bad rv.II size");
|
CHECK_AND_ASSERT_MES(II.size() == rows, false, "Bad II size");
|
||||||
CHECK_AND_ASSERT_MES(rv.ss.size() == cols, false, "Bad rv.ss size");
|
CHECK_AND_ASSERT_MES(rv.ss.size() == cols, false, "Bad rv.ss size");
|
||||||
for (size_t i = 0; i < cols; ++i) {
|
for (size_t i = 0; i < cols; ++i) {
|
||||||
CHECK_AND_ASSERT_MES(rv.ss[i].size() == rows, false, "rv.ss is not rectangular");
|
CHECK_AND_ASSERT_MES(rv.ss[i].size() == rows, false, "rv.ss is not rectangular");
|
||||||
|
@ -246,7 +246,7 @@ namespace rct {
|
||||||
key c_old = copy(rv.cc);
|
key c_old = copy(rv.cc);
|
||||||
vector<geDsmp> Ip(rows);
|
vector<geDsmp> Ip(rows);
|
||||||
for (i= 0 ; i< rows ; i++) {
|
for (i= 0 ; i< rows ; i++) {
|
||||||
precomp(Ip[i].k, rv.II[i]);
|
precomp(Ip[i].k, II[i]);
|
||||||
}
|
}
|
||||||
unsigned char m2[128];
|
unsigned char m2[128];
|
||||||
memcpy(m2, message.bytes, 32);
|
memcpy(m2, message.bytes, 32);
|
||||||
|
@ -334,7 +334,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) {
|
mgSig proveRctMG(const ctkeyM & pubs, const ctkeyV & inSk, const ctkeyV &outSk, const ctkeyV & outPk, unsigned int index, key txnFeeKey, const key &base_hash) {
|
||||||
mgSig mg;
|
mgSig mg;
|
||||||
//setup vars
|
//setup vars
|
||||||
size_t cols = pubs.size();
|
size_t cols = pubs.size();
|
||||||
|
@ -378,7 +378,9 @@ namespace rct {
|
||||||
for (size_t j = 0; j < outPk.size(); j++) {
|
for (size_t j = 0; j < outPk.size(); j++) {
|
||||||
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..
|
||||||
}
|
}
|
||||||
key message = cn_fast_hash(outPk);
|
ctkeyV signed_data = outPk;
|
||||||
|
signed_data.push_back(ctkey({base_hash, identity()}));
|
||||||
|
key message = cn_fast_hash(signed_data);
|
||||||
return MLSAG_Gen(message, M, sk, index);
|
return MLSAG_Gen(message, M, sk, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,7 +393,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 ctkeyM & pubs, const ctkeyV & outPk, key txnFeeKey) {
|
bool verRctMG(mgSig mg, const keyV &II, const ctkeyM & pubs, const ctkeyV & outPk, key txnFeeKey, const key &base_hash) {
|
||||||
//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");
|
||||||
|
@ -422,10 +424,12 @@ namespace rct {
|
||||||
//subtract txn fee output in last row
|
//subtract txn fee output in last row
|
||||||
subKeys(M[i][rows], M[i][rows], txnFeeKey);
|
subKeys(M[i][rows], M[i][rows], txnFeeKey);
|
||||||
}
|
}
|
||||||
key message = cn_fast_hash(outPk);
|
ctkeyV signed_data = outPk;
|
||||||
|
signed_data.push_back(ctkey({base_hash, identity()}));
|
||||||
|
key message = cn_fast_hash(signed_data);
|
||||||
DP("message:");
|
DP("message:");
|
||||||
DP(message);
|
DP(message);
|
||||||
return MLSAG_Ver(message, M, mg);
|
return MLSAG_Ver(message, M, mg, II);
|
||||||
}
|
}
|
||||||
|
|
||||||
//These functions get keys from blockchain
|
//These functions get keys from blockchain
|
||||||
|
@ -470,7 +474,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, unsigned int index) {
|
rctSig genRct(const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> amounts, const ctkeyM &mixRing, const key &base_hash, 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) {
|
||||||
|
@ -513,15 +517,16 @@ namespace rct {
|
||||||
key txnFeeKey = scalarmultH(d2h(rv.txnFee));
|
key txnFeeKey = scalarmultH(d2h(rv.txnFee));
|
||||||
|
|
||||||
rv.mixRing = mixRing;
|
rv.mixRing = mixRing;
|
||||||
rv.MG = proveRctMG(rv.mixRing, inSk, outSk, rv.outPk, index, txnFeeKey);
|
rv.base_hash = base_hash;
|
||||||
|
rv.MG = proveRctMG(rv.mixRing, inSk, outSk, rv.outPk, index, txnFeeKey, base_hash);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
rctSig genRct(const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> amounts, const int mixin) {
|
rctSig genRct(const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> amounts, const key &base_hash, 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, index);
|
return genRct(inSk, destinations, amounts, mixRing, base_hash, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
//RingCT protocol
|
//RingCT protocol
|
||||||
|
@ -534,7 +539,7 @@ 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) {
|
bool verRct(const rctSig & rv, const ctkeyM &mixRing, const keyV &II, const key &base_hash) {
|
||||||
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");
|
||||||
|
|
||||||
|
@ -552,7 +557,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, rv.mixRing, rv.outPk, txnFeeKey);
|
bool mgVerd = verRctMG(rv.MG, II, mixRing, rv.outPk, txnFeeKey, base_hash);
|
||||||
DP("mg sig verified?");
|
DP("mg sig verified?");
|
||||||
DP(mgVerd);
|
DP(mgVerd);
|
||||||
|
|
||||||
|
@ -563,6 +568,9 @@ namespace rct {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
bool verRct(const rctSig & rv) {
|
||||||
|
return verRct(rv, rv.mixRing, rv.MG.II, rv.base_hash);
|
||||||
|
}
|
||||||
|
|
||||||
//RingCT protocol
|
//RingCT protocol
|
||||||
//genRct:
|
//genRct:
|
||||||
|
|
|
@ -91,7 +91,7 @@ namespace rct {
|
||||||
// Ver verifies that the MG sig was created correctly
|
// Ver verifies that the MG sig was created correctly
|
||||||
keyV keyImageV(const keyV &xx);
|
keyV keyImageV(const keyV &xx);
|
||||||
mgSig MLSAG_Gen(key message, const keyM & pk, const keyV & xx, const unsigned int index);
|
mgSig MLSAG_Gen(key message, const keyM & pk, const keyV & xx, const unsigned int index);
|
||||||
bool MLSAG_Ver(key message, const keyM &pk, const mgSig &sig);
|
bool MLSAG_Ver(key message, const keyM &pk, const mgSig &sig, const keyV &II);
|
||||||
//mgSig MLSAG_Gen_Old(const keyM & pk, const keyV & xx, const int index);
|
//mgSig MLSAG_Gen_Old(const keyM & pk, const keyV & xx, const int index);
|
||||||
|
|
||||||
//proveRange and verRange
|
//proveRange and verRange
|
||||||
|
@ -112,8 +112,8 @@ 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);
|
mgSig proveRctMG(const ctkeyM & pubs, const ctkeyV & inSk, const keyV &outMasks, const ctkeyV & outPk, unsigned int index, key txnFee, const key &base_hash);
|
||||||
bool verRctMG(mgSig mg, const ctkeyM & pubs, const ctkeyV & outPk, key txnFee);
|
bool verRctMG(mgSig mg, const ctkeyM & pubs, const ctkeyV & outPk, key txnFee, const key &base_hash);
|
||||||
|
|
||||||
//These functions get keys from blockchain
|
//These functions get keys from blockchain
|
||||||
//replace these when connecting blockchain
|
//replace these when connecting blockchain
|
||||||
|
@ -133,9 +133,10 @@ 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, unsigned int index);
|
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 ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> amounts, const int mixin);
|
rctSig genRct(const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> amounts, const key &bash_hash, const int mixin);
|
||||||
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);
|
||||||
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);
|
||||||
|
|
||||||
|
|
|
@ -148,7 +148,16 @@ namespace rct {
|
||||||
BEGIN_SERIALIZE_OBJECT()
|
BEGIN_SERIALIZE_OBJECT()
|
||||||
FIELD(ss)
|
FIELD(ss)
|
||||||
FIELD(cc)
|
FIELD(cc)
|
||||||
FIELD(II)
|
if (II.size() == 0) {
|
||||||
|
// loading
|
||||||
|
FIELD(II)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// saving
|
||||||
|
keyV II;
|
||||||
|
II.push_back(this->II.back());
|
||||||
|
FIELD(II)
|
||||||
|
}
|
||||||
END_SERIALIZE()
|
END_SERIALIZE()
|
||||||
};
|
};
|
||||||
//contains the data for an asnl sig
|
//contains the data for an asnl sig
|
||||||
|
@ -181,14 +190,16 @@ namespace rct {
|
||||||
vector<ecdhTuple> ecdhInfo;
|
vector<ecdhTuple> ecdhInfo;
|
||||||
ctkeyV outPk;
|
ctkeyV outPk;
|
||||||
xmr_amount txnFee;
|
xmr_amount txnFee;
|
||||||
|
key base_hash;
|
||||||
|
|
||||||
BEGIN_SERIALIZE_OBJECT()
|
BEGIN_SERIALIZE_OBJECT()
|
||||||
FIELD(rangeSigs)
|
FIELD(rangeSigs)
|
||||||
FIELD(MG)
|
FIELD(MG)
|
||||||
FIELD(mixRing)
|
// FIELD(mixRing) - not serialized, it can be reconstructed
|
||||||
FIELD(ecdhInfo)
|
FIELD(ecdhInfo)
|
||||||
FIELD(outPk)
|
FIELD(outPk)
|
||||||
FIELD(txnFee)
|
FIELD(txnFee)
|
||||||
|
// FIELD(base_hash) - not serialized, it can be reconstructed
|
||||||
END_SERIALIZE()
|
END_SERIALIZE()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -296,9 +307,11 @@ namespace rct {
|
||||||
static inline rct::key pk2rct(const crypto::public_key &pk) { rct::key k; memcpy(&k, &pk, 32); return k; }
|
static inline rct::key pk2rct(const crypto::public_key &pk) { rct::key k; memcpy(&k, &pk, 32); return k; }
|
||||||
static inline rct::key sk2rct(const crypto::secret_key &sk) { rct::key k; memcpy(&k, &sk, 32); return k; }
|
static inline rct::key sk2rct(const crypto::secret_key &sk) { rct::key k; memcpy(&k, &sk, 32); return k; }
|
||||||
static inline rct::key ki2rct(const crypto::key_image &ki) { rct::key k; memcpy(&k, &ki, 32); return k; }
|
static inline rct::key ki2rct(const crypto::key_image &ki) { rct::key k; memcpy(&k, &ki, 32); return k; }
|
||||||
|
static inline rct::key hash2rct(const crypto::hash &h) { rct::key k; memcpy(&k, &h, 32); return k; }
|
||||||
static inline crypto::public_key rct2pk(const rct::key &k) { crypto::public_key pk; memcpy(&pk, &k, 32); return pk; }
|
static inline crypto::public_key rct2pk(const rct::key &k) { crypto::public_key pk; memcpy(&pk, &k, 32); return pk; }
|
||||||
static inline crypto::secret_key rct2sk(const rct::key &k) { crypto::secret_key sk; memcpy(&sk, &k, 32); return sk; }
|
static inline crypto::secret_key rct2sk(const rct::key &k) { crypto::secret_key sk; memcpy(&sk, &k, 32); return sk; }
|
||||||
static inline crypto::key_image rct2ki(const rct::key &k) { crypto::key_image ki; memcpy(&ki, &k, 32); return ki; }
|
static inline crypto::key_image rct2ki(const rct::key &k) { crypto::key_image ki; memcpy(&ki, &k, 32); return ki; }
|
||||||
|
static inline crypto::hash rct2hash(const rct::key &k) { crypto::hash h; memcpy(&h, &k, 32); return h; }
|
||||||
static inline bool operator==(const rct::key &k0, const crypto::public_key &k1) { return !memcmp(&k0, &k1, 32); }
|
static inline bool operator==(const rct::key &k0, const crypto::public_key &k1) { return !memcmp(&k0, &k1, 32); }
|
||||||
static inline bool operator!=(const rct::key &k0, const crypto::public_key &k1) { return memcmp(&k0, &k1, 32); }
|
static inline bool operator!=(const rct::key &k0, const crypto::public_key &k1) { return memcmp(&k0, &k1, 32); }
|
||||||
}
|
}
|
||||||
|
|
|
@ -3237,16 +3237,19 @@ static size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs)
|
||||||
|
|
||||||
// rangeSigs
|
// rangeSigs
|
||||||
size += (2*64*32+32+64*32) * n_outputs;
|
size += (2*64*32+32+64*32) * n_outputs;
|
||||||
// MG
|
|
||||||
size += 32 * (mixin+1) * n_inputs + 32 + 32 * n_inputs;
|
// MG - only the last slot of II is saved, the rest can be reconstructed
|
||||||
// mixRing
|
size += 32 * (mixin+1) * n_inputs + 32 + 32 * (/*n_inputs+*/1) ;
|
||||||
size += 2 * 32 * (mixin+1) * n_inputs;
|
|
||||||
|
// mixRing - not serialized, can be reconstructed
|
||||||
|
/* size += 2 * 32 * (mixin+1) * n_inputs; */
|
||||||
|
|
||||||
// ecdhInfo
|
// ecdhInfo
|
||||||
size += 3 * 32 * n_outputs;
|
size += 3 * 32 * n_outputs;
|
||||||
// outPk
|
// outPk
|
||||||
size += 2 * 32 * n_outputs;
|
size += 2 * 32 * n_outputs;
|
||||||
|
|
||||||
LOG_PRINT_L2("estimated rct tx size for " << n_inputs << " at mixin " << mixin << " and " << n_outputs << ": " << size);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -131,7 +131,7 @@ TEST(ringct, MG_sigs)
|
||||||
}
|
}
|
||||||
key message = identity();
|
key message = identity();
|
||||||
mgSig IIccss = MLSAG_Gen(message, P, sk, ind);
|
mgSig IIccss = MLSAG_Gen(message, P, sk, ind);
|
||||||
ASSERT_TRUE(MLSAG_Ver(message, P, IIccss));
|
ASSERT_TRUE(MLSAG_Ver(message, P, IIccss, IIccss.II));
|
||||||
|
|
||||||
//#MG sig: false one
|
//#MG sig: false one
|
||||||
N = 3;// #cols
|
N = 3;// #cols
|
||||||
|
@ -152,7 +152,7 @@ TEST(ringct, MG_sigs)
|
||||||
}
|
}
|
||||||
sk[2] = skGen();//asume we don't know one of the private keys..
|
sk[2] = skGen();//asume we don't know one of the private keys..
|
||||||
IIccss = MLSAG_Gen(message, P, sk, ind);
|
IIccss = MLSAG_Gen(message, P, sk, ind);
|
||||||
ASSERT_FALSE(MLSAG_Ver(message, P, IIccss));
|
ASSERT_FALSE(MLSAG_Ver(message, P, IIccss, IIccss.II));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ringct, range_proofs)
|
TEST(ringct, range_proofs)
|
||||||
|
|
|
@ -576,11 +576,10 @@ TEST(Serialization, serializes_ringct_types)
|
||||||
ASSERT_TRUE(mg0.ss[n] == mg1.ss[n]);
|
ASSERT_TRUE(mg0.ss[n] == mg1.ss[n]);
|
||||||
}
|
}
|
||||||
ASSERT_TRUE(mg0.cc == mg1.cc);
|
ASSERT_TRUE(mg0.cc == mg1.cc);
|
||||||
ASSERT_TRUE(mg0.II.size() == mg1.II.size());
|
|
||||||
for (size_t n = 0; n < mg0.II.size(); ++n)
|
// mixRing and II are not serialized, they are meant to be reconstructed
|
||||||
{
|
ASSERT_TRUE(mg1.II.size() == 1);
|
||||||
ASSERT_TRUE(mg0.II[n] == mg1.II[n]);
|
ASSERT_TRUE(mg1.II[0] == mg0.II.back());
|
||||||
}
|
|
||||||
|
|
||||||
rg0 = s0.rangeSigs.front();
|
rg0 = s0.rangeSigs.front();
|
||||||
ASSERT_TRUE(serialization::dump_binary(rg0, blob));
|
ASSERT_TRUE(serialization::dump_binary(rg0, blob));
|
||||||
|
@ -600,20 +599,13 @@ TEST(Serialization, serializes_ringct_types)
|
||||||
ASSERT_TRUE(s0.MG.ss[n] == s1.MG.ss[n]);
|
ASSERT_TRUE(s0.MG.ss[n] == s1.MG.ss[n]);
|
||||||
}
|
}
|
||||||
ASSERT_TRUE(s0.MG.cc == s1.MG.cc);
|
ASSERT_TRUE(s0.MG.cc == s1.MG.cc);
|
||||||
ASSERT_TRUE(s0.MG.II.size() == s1.MG.II.size());
|
// mixRing and II are not serialized, they are meant to be reconstructed
|
||||||
for (size_t n = 0; n < s0.MG.II.size(); ++n)
|
ASSERT_TRUE(s1.MG.II.size() == 1);
|
||||||
{
|
ASSERT_TRUE(s1.MG.II[0] == s0.MG.II.back());
|
||||||
ASSERT_TRUE(s0.MG.II[n] == s1.MG.II[n]);
|
|
||||||
}
|
// mixRing and II are not serialized, they are meant to be reconstructed
|
||||||
ASSERT_TRUE(s0.mixRing.size() == s1.mixRing.size());
|
ASSERT_TRUE(s1.mixRing.size() == 0);
|
||||||
for (size_t n = 0; n < s0.mixRing.size(); ++n)
|
|
||||||
{
|
|
||||||
ASSERT_TRUE(s0.mixRing[n].size() == s1.mixRing[n].size());
|
|
||||||
for (size_t i = 0; i < s0.mixRing[n].size(); ++i)
|
|
||||||
{
|
|
||||||
ASSERT_TRUE(!memcmp(&s0.mixRing[n][i], &s1.mixRing[n][i], sizeof(s0.mixRing[n][i])));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ASSERT_TRUE(s0.ecdhInfo.size() == s1.ecdhInfo.size());
|
ASSERT_TRUE(s0.ecdhInfo.size() == s1.ecdhInfo.size());
|
||||||
for (size_t n = 0; n < s0.ecdhInfo.size(); ++n)
|
for (size_t n = 0; n < s0.ecdhInfo.size(); ++n)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue