diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index f6f56b086..91a9d5d6f 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -2475,12 +2475,12 @@ bool Blockchain::check_tx_inputs(const transaction& tx, tx_verification_context 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, and always do outPk - // all MGs should have the same II size (1) + // all MGs should have empty II for (size_t n = 0; n < tx.rct_signatures.MGs.size(); ++n) { - if (tx.rct_signatures.MGs[n].II.size() != 1) + if (tx.rct_signatures.MGs[n].II.size() != 0) { - LOG_PRINT_L1("Failed to check ringct signatures: mismatched MGs II sizes"); + LOG_PRINT_L1("Failed to check ringct signatures: non empty MGs II"); return false; } } @@ -2489,7 +2489,6 @@ bool Blockchain::check_tx_inputs(const transaction& tx, tx_verification_context for (size_t n = 0; n < tx.vin.size(); ++n) { reconstructed_II[n].push_back(rct::ki2rct(boost::get(tx.vin[n]).k_image)); - reconstructed_II[n].push_back(tx.rct_signatures.MGs[n].II[0]); } if (tx.rct_signatures.outPk.size() != tx.vout.size()) @@ -2579,7 +2578,7 @@ bool Blockchain::check_tx_inputs(const transaction& tx, tx_verification_context // if the tx already has a non empty mixRing and/or II, use them, // else reconstruct them. Always do outPk. 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; + const rct::keyV &II = tx.rct_signatures.MG.II.empty() ? reconstructed_II : tx.rct_signatures.MG.II; const rct::ctkeyV outPk = reconstructed_outPk; // RCT needs the same mixin for all inputs @@ -2604,14 +2603,13 @@ bool Blockchain::check_tx_inputs(const transaction& tx, tx_verification_context } } - if (tx.rct_signatures.MG.II.size() == 1) + if (tx.rct_signatures.MG.II.empty()) { reconstructed_II.resize(tx.vin.size()); for (size_t n = 0; n < tx.vin.size(); ++n) { reconstructed_II[n] = rct::ki2rct(boost::get(tx.vin[n]).k_image); } - reconstructed_II.push_back(tx.rct_signatures.MG.II.back()); } if (tx.rct_signatures.outPk.size() != tx.vout.size()) @@ -2657,7 +2655,7 @@ bool Blockchain::check_tx_inputs(const transaction& tx, tx_verification_context } } - if (II.size() != 1 + tx.vin.size()) + if (II.size() != tx.vin.size()) { LOG_PRINT_L1("Failed to check ringct signatures: mismatched II/vin sizes"); return false; diff --git a/src/cryptonote_core/cryptonote_boost_serialization.h b/src/cryptonote_core/cryptonote_boost_serialization.h index 41f864803..8a82aa7a7 100644 --- a/src/cryptonote_core/cryptonote_boost_serialization.h +++ b/src/cryptonote_core/cryptonote_boost_serialization.h @@ -209,19 +209,12 @@ namespace boost a & x.s; } - inline void serialize(boost::archive::binary_iarchive &a, rct::mgSig &x, const boost::serialization::version_type ver) - { - a & x.ss; - a & x.cc; - x.II.resize(1); - a & x.II[0]; - } - - inline void serialize(boost::archive::binary_oarchive &a, rct::mgSig &x, const boost::serialization::version_type ver) + template + inline void serialize(Archive &a, rct::mgSig &x, const boost::serialization::version_type ver) { a & x.ss; a & x.cc; - a & x.II.back(); + // a & x.II; // not serialized, we can recover it from the tx vin } template diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 0d4fbee1a..c252645f8 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -148,7 +148,7 @@ namespace rct { // 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 // Ver verifies that the MG sig was created correctly - 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, size_t dsRows) { mgSig rv; size_t cols = pk.size(); CHECK_AND_ASSERT_THROW_MES(cols >= 2, "Error! What is c if cols = 1!"); @@ -159,20 +159,21 @@ namespace rct { CHECK_AND_ASSERT_THROW_MES(pk[i].size() == rows, "pk is not rectangular"); } CHECK_AND_ASSERT_THROW_MES(xx.size() == rows, "Bad xx size"); + CHECK_AND_ASSERT_THROW_MES(dsRows <= rows, "Bad dsRows size"); - size_t i = 0, j = 0; + size_t i = 0, j = 0, ii = 0; key c, c_old, L, R, Hi; sc_0(c_old.bytes); - vector Ip(rows); - rv.II = keyV(rows); - rv.ss = keyM(cols, rv.II); + vector Ip(dsRows); + rv.II = keyV(dsRows); keyV alpha(rows); keyV aG(rows); - keyV aHP(rows); - keyV toHash(1 + 3 * rows); + rv.ss = keyM(cols, aG); + keyV aHP(dsRows); + keyV toHash(1 + 3 * dsRows + 2 * (rows - dsRows)); toHash[0] = message; DP("here1"); - for (i = 0; i < rows; i++) { + for (i = 0; i < dsRows; i++) { skpkGen(alpha[i], aG[i]); //need to save alphas for later.. Hi = hashToPoint(pk[index][i]); aHP[i] = scalarmultKey(Hi, alpha[i]); @@ -182,6 +183,13 @@ namespace rct { rv.II[i] = scalarmultKey(Hi, xx[i]); precomp(Ip[i].k, rv.II[i]); } + size_t ndsRows = 3 * dsRows; //non Double Spendable Rows (see identity chains paper) + for (i = dsRows, ii = 0 ; i < rows ; i++, ii++) { + skpkGen(alpha[i], aG[i]); //need to save alphas for later.. + toHash[ndsRows + 2 * ii + 1] = pk[index][i]; + toHash[ndsRows + 2 * ii + 2] = aG[i]; + } + c_old = hash_to_scalar(toHash); @@ -193,7 +201,7 @@ namespace rct { rv.ss[i] = skvGen(rows); sc_0(c.bytes); - for (j = 0; j < rows; j++) { + for (j = 0; j < dsRows; j++) { addKeys2(L, rv.ss[i][j], c_old, pk[i][j]); hashToPoint(Hi, pk[i][j]); addKeys3(R, rv.ss[i][j], Hi, c_old, Ip[j].k); @@ -201,6 +209,11 @@ namespace rct { toHash[3 * j + 2] = L; toHash[3 * j + 3] = R; } + for (j = dsRows, ii = 0; j < rows; j++, ii++) { + addKeys2(L, rv.ss[i][j], c_old, pk[i][j]); + toHash[ndsRows + 2 * ii + 1] = pk[i][j]; + toHash[ndsRows + 2 * ii + 2] = L; + } c = hash_to_scalar(toHash); copy(c_old, c); i = (i + 1) % cols; @@ -224,7 +237,7 @@ namespace rct { // 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 // Ver verifies that the MG sig was created correctly - bool MLSAG_Ver(key message, const keyM & pk, const mgSig & rv, const keyV &II) { + bool MLSAG_Ver(key message, const keyM & pk, const mgSig & rv, const keyV &II, size_t dsRows) { size_t cols = pk.size(); CHECK_AND_ASSERT_MES(cols >= 2, false, "Error! What is c if cols = 1!"); @@ -233,25 +246,27 @@ namespace rct { 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(II.size() == rows, false, "Bad II size"); + CHECK_AND_ASSERT_MES(II.size() == dsRows, false, "Bad II size"); CHECK_AND_ASSERT_MES(rv.ss.size() == cols, false, "Bad rv.ss size"); 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(dsRows <= rows, false, "Bad dsRows value"); - size_t i = 0, j = 0; + size_t i = 0, j = 0, ii = 0; key c, L, R, Hi; key c_old = copy(rv.cc); - vector Ip(rows); - for (i= 0 ; i< rows ; i++) { + vector Ip(dsRows); + for (i = 0 ; i < dsRows ; i++) { precomp(Ip[i].k, II[i]); } - keyV toHash(1 + 3 * rows); + size_t ndsRows = 3 * dsRows; //non Double Spendable Rows (see identity chains paper + keyV toHash(1 + 3 * dsRows + 2 * (rows - dsRows)); toHash[0] = message; i = 0; while (i < cols) { sc_0(c.bytes); - for (j = 0; j < rows; j++) { + for (j = 0; j < dsRows; j++) { addKeys2(L, rv.ss[i][j], c_old, pk[i][j]); hashToPoint(Hi, pk[i][j]); addKeys3(R, rv.ss[i][j], Hi, c_old, Ip[j].k); @@ -259,6 +274,11 @@ namespace rct { toHash[3 * j + 2] = L; toHash[3 * j + 3] = R; } + for (j = dsRows, ii = 0 ; j < rows ; j++, ii++) { + addKeys2(L, rv.ss[i][j], c_old, pk[i][j]); + toHash[ndsRows + 2 * ii + 1] = pk[i][j]; + toHash[ndsRows + 2 * ii + 2] = L; + } c = hash_to_scalar(toHash); copy(c_old, c); i = (i + 1); @@ -376,7 +396,7 @@ namespace rct { ctkeyV signed_data = outPk; signed_data.push_back(ctkey({message, identity()})); key msg = cn_fast_hash(signed_data); - return MLSAG_Gen(msg, M, sk, index); + return MLSAG_Gen(msg, M, sk, index, rows); } @@ -403,7 +423,7 @@ namespace rct { sk[0] = copy(inSk.dest); sc_sub(sk[1].bytes, inSk.mask.bytes, a.bytes); } - return MLSAG_Gen(message, M, sk, index); + return MLSAG_Gen(message, M, sk, index, rows); } @@ -451,7 +471,7 @@ namespace rct { key msg = cn_fast_hash(signed_data); DP("message:"); DP(msg); - return MLSAG_Ver(msg, M, mg, II); + return MLSAG_Ver(msg, M, mg, II, rows); } //Ring-ct Simple MG sigs @@ -472,7 +492,7 @@ namespace rct { subKeys(M[i][1], pubs[i].mask, C); } //DP(C); - return MLSAG_Ver(message, M, mg, II); + return MLSAG_Ver(message, M, mg, II, rows); } //These functions get keys from blockchain @@ -729,7 +749,7 @@ namespace rct { { for (size_t n = 0; n < II->size(); ++n) { - CHECK_AND_ASSERT_MES((*II)[n].size() == 2, false, "Bad II size"); + CHECK_AND_ASSERT_MES((*II)[n].size() == 1, false, "Bad II size"); } } diff --git a/src/ringct/rctSigs.h b/src/ringct/rctSigs.h index d150e7180..558af22fd 100644 --- a/src/ringct/rctSigs.h +++ b/src/ringct/rctSigs.h @@ -90,8 +90,8 @@ namespace rct { // the signer knows a secret key for each row in that column // Ver verifies that the MG sig was created correctly keyV keyImageV(const keyV &xx); - 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, const keyV &II); + mgSig MLSAG_Gen(key message, const keyM & pk, const keyV & xx, const unsigned int index, size_t dsRows); + bool MLSAG_Ver(key message, const keyM &pk, const mgSig &sig, const keyV &II, size_t dsRows); //mgSig MLSAG_Gen_Old(const keyM & pk, const keyV & xx, const int index); //proveRange and verRange diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h index 1ba280aba..8df403c68 100644 --- a/src/ringct/rctTypes.h +++ b/src/ringct/rctTypes.h @@ -148,16 +148,7 @@ namespace rct { BEGIN_SERIALIZE_OBJECT() FIELD(ss) FIELD(cc) - if (II.size() == 0) { - // loading - FIELD(II) - } - else { - // saving - keyV II; - II.push_back(this->II.back()); - FIELD(II) - } + // FIELD(II) - not serialized, it can be reconstructed END_SERIALIZE() }; //contains the data for an asnl sig diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp index 0da23c0d2..9311ca016 100644 --- a/tests/unit_tests/serialization.cpp +++ b/tests/unit_tests/serialization.cpp @@ -582,8 +582,7 @@ TEST(Serialization, serializes_ringct_types) ASSERT_TRUE(mg0.cc == mg1.cc); // mixRing and II are not serialized, they are meant to be reconstructed - ASSERT_TRUE(mg1.II.size() == 1); - ASSERT_TRUE(mg1.II[0] == mg0.II.back()); + ASSERT_TRUE(mg1.II.empty()); rg0 = s0.rangeSigs.front(); ASSERT_TRUE(serialization::dump_binary(rg0, blob)); @@ -605,8 +604,7 @@ TEST(Serialization, serializes_ringct_types) } ASSERT_TRUE(s0.MG.cc == s1.MG.cc); // mixRing and II are not serialized, they are meant to be reconstructed - ASSERT_TRUE(s1.MG.II.size() == 1); - ASSERT_TRUE(s1.MG.II[0] == s0.MG.II.back()); + ASSERT_TRUE(s1.MGs[0].II.empty()); // mixRing and II are not serialized, they are meant to be reconstructed ASSERT_TRUE(s1.mixRing.size() == 0);