From c5be4b0beaaa7a703d4e2b84aa9f3c727bf992df Mon Sep 17 00:00:00 2001 From: Shen Noether Date: Mon, 8 Aug 2016 12:54:00 +0100 Subject: [PATCH] rct: avoid the need for the last II element This element is used in the generation of the MLSAG, but isn't needed in verification. Also misc changes in the cryptonote code to match, by mooo. --- src/cryptonote_core/blockchain.cpp | 14 ++--- .../cryptonote_boost_serialization.h | 13 +--- src/ringct/rctSigs.cpp | 62 ++++++++++++------- src/ringct/rctSigs.h | 4 +- src/ringct/rctTypes.h | 11 +--- tests/unit_tests/serialization.cpp | 6 +- 6 files changed, 55 insertions(+), 55 deletions(-) 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) + template + inline void serialize(Archive &a, rct::mgSig &x, const boost::serialization::version_type ver) { a & x.ss; a & x.cc; - x.II.resize(1); - a & x.II[0]; - } - - inline void serialize(boost::archive::binary_oarchive &a, rct::mgSig &x, const boost::serialization::version_type ver) - { - a & x.ss; - a & x.cc; - a & x.II.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);