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.
This commit is contained in:
Shen Noether 2016-08-08 12:54:00 +01:00 committed by moneromooo-monero
parent a47ceee83b
commit c5be4b0bea
No known key found for this signature in database
GPG key ID: 686F07454D6CEFC3
6 changed files with 55 additions and 55 deletions

View file

@ -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; 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 // 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) 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; 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) for (size_t n = 0; n < tx.vin.size(); ++n)
{ {
reconstructed_II[n].push_back(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]);
} }
if (tx.rct_signatures.outPk.size() != tx.vout.size()) 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, // if the tx already has a non empty mixRing and/or II, use them,
// else reconstruct them. Always do outPk. // else reconstruct them. Always do outPk.
const rct::ctkeyM &mixRing = tx.rct_signatures.mixRing.empty() ? reconstructed_mixRing : tx.rct_signatures.mixRing; 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; const rct::ctkeyV outPk = reconstructed_outPk;
// RCT needs the same mixin for all inputs // 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()); 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] = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image);
} }
reconstructed_II.push_back(tx.rct_signatures.MG.II.back());
} }
if (tx.rct_signatures.outPk.size() != tx.vout.size()) 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"); LOG_PRINT_L1("Failed to check ringct signatures: mismatched II/vin sizes");
return false; return false;

View file

@ -209,19 +209,12 @@ namespace boost
a & x.s; a & x.s;
} }
inline void serialize(boost::archive::binary_iarchive &a, rct::mgSig &x, const boost::serialization::version_type ver) template <class Archive>
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;
x.II.resize(1); // a & x.II; // not serialized, we can recover it from the tx vin
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>

View file

@ -148,7 +148,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
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; mgSig rv;
size_t cols = pk.size(); size_t cols = pk.size();
CHECK_AND_ASSERT_THROW_MES(cols >= 2, "Error! What is c if cols = 1!"); 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(pk[i].size() == rows, "pk is not rectangular");
} }
CHECK_AND_ASSERT_THROW_MES(xx.size() == rows, "Bad xx size"); 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; key c, c_old, L, R, Hi;
sc_0(c_old.bytes); sc_0(c_old.bytes);
vector<geDsmp> Ip(rows); vector<geDsmp> Ip(dsRows);
rv.II = keyV(rows); rv.II = keyV(dsRows);
rv.ss = keyM(cols, rv.II);
keyV alpha(rows); keyV alpha(rows);
keyV aG(rows); keyV aG(rows);
keyV aHP(rows); rv.ss = keyM(cols, aG);
keyV toHash(1 + 3 * rows); keyV aHP(dsRows);
keyV toHash(1 + 3 * dsRows + 2 * (rows - dsRows));
toHash[0] = message; toHash[0] = message;
DP("here1"); 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.. skpkGen(alpha[i], aG[i]); //need to save alphas for later..
Hi = hashToPoint(pk[index][i]); Hi = hashToPoint(pk[index][i]);
aHP[i] = scalarmultKey(Hi, alpha[i]); aHP[i] = scalarmultKey(Hi, alpha[i]);
@ -182,6 +183,13 @@ namespace rct {
rv.II[i] = scalarmultKey(Hi, xx[i]); rv.II[i] = scalarmultKey(Hi, xx[i]);
precomp(Ip[i].k, rv.II[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); c_old = hash_to_scalar(toHash);
@ -193,7 +201,7 @@ namespace rct {
rv.ss[i] = skvGen(rows); rv.ss[i] = skvGen(rows);
sc_0(c.bytes); 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]); addKeys2(L, rv.ss[i][j], c_old, pk[i][j]);
hashToPoint(Hi, pk[i][j]); hashToPoint(Hi, pk[i][j]);
addKeys3(R, rv.ss[i][j], Hi, c_old, Ip[j].k); 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 + 2] = L;
toHash[3 * j + 3] = R; 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); c = hash_to_scalar(toHash);
copy(c_old, c); copy(c_old, c);
i = (i + 1) % cols; i = (i + 1) % cols;
@ -224,7 +237,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, 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(); 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!");
@ -233,25 +246,27 @@ 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(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"); 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");
} }
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, L, R, Hi;
key c_old = copy(rv.cc); key c_old = copy(rv.cc);
vector<geDsmp> Ip(rows); vector<geDsmp> Ip(dsRows);
for (i= 0 ; i< rows ; i++) { for (i = 0 ; i < dsRows ; i++) {
precomp(Ip[i].k, II[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; toHash[0] = message;
i = 0; i = 0;
while (i < cols) { while (i < cols) {
sc_0(c.bytes); 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]); addKeys2(L, rv.ss[i][j], c_old, pk[i][j]);
hashToPoint(Hi, pk[i][j]); hashToPoint(Hi, pk[i][j]);
addKeys3(R, rv.ss[i][j], Hi, c_old, Ip[j].k); 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 + 2] = L;
toHash[3 * j + 3] = R; 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); c = hash_to_scalar(toHash);
copy(c_old, c); copy(c_old, c);
i = (i + 1); i = (i + 1);
@ -376,7 +396,7 @@ namespace rct {
ctkeyV signed_data = outPk; ctkeyV signed_data = outPk;
signed_data.push_back(ctkey({message, identity()})); signed_data.push_back(ctkey({message, identity()}));
key msg = cn_fast_hash(signed_data); 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); sk[0] = copy(inSk.dest);
sc_sub(sk[1].bytes, inSk.mask.bytes, a.bytes); 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); key msg = cn_fast_hash(signed_data);
DP("message:"); DP("message:");
DP(msg); DP(msg);
return MLSAG_Ver(msg, M, mg, II); return MLSAG_Ver(msg, M, mg, II, rows);
} }
//Ring-ct Simple MG sigs //Ring-ct Simple MG sigs
@ -472,7 +492,7 @@ namespace rct {
subKeys(M[i][1], pubs[i].mask, C); subKeys(M[i][1], pubs[i].mask, C);
} }
//DP(C); //DP(C);
return MLSAG_Ver(message, M, mg, II); return MLSAG_Ver(message, M, mg, II, rows);
} }
//These functions get keys from blockchain //These functions get keys from blockchain
@ -729,7 +749,7 @@ namespace rct {
{ {
for (size_t n = 0; n < II->size(); ++n) 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");
} }
} }

View file

@ -90,8 +90,8 @@ namespace rct {
// 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
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, size_t dsRows);
bool MLSAG_Ver(key message, const keyM &pk, const mgSig &sig, const keyV &II); 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); //mgSig MLSAG_Gen_Old(const keyM & pk, const keyV & xx, const int index);
//proveRange and verRange //proveRange and verRange

View file

@ -148,16 +148,7 @@ namespace rct {
BEGIN_SERIALIZE_OBJECT() BEGIN_SERIALIZE_OBJECT()
FIELD(ss) FIELD(ss)
FIELD(cc) FIELD(cc)
if (II.size() == 0) { // FIELD(II) - not serialized, it can be reconstructed
// 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

View file

@ -582,8 +582,7 @@ TEST(Serialization, serializes_ringct_types)
ASSERT_TRUE(mg0.cc == mg1.cc); ASSERT_TRUE(mg0.cc == mg1.cc);
// mixRing and II are not serialized, they are meant to be reconstructed // mixRing and II are not serialized, they are meant to be reconstructed
ASSERT_TRUE(mg1.II.size() == 1); ASSERT_TRUE(mg1.II.empty());
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));
@ -605,8 +604,7 @@ TEST(Serialization, serializes_ringct_types)
} }
ASSERT_TRUE(s0.MG.cc == s1.MG.cc); ASSERT_TRUE(s0.MG.cc == s1.MG.cc);
// mixRing and II are not serialized, they are meant to be reconstructed // mixRing and II are not serialized, they are meant to be reconstructed
ASSERT_TRUE(s1.MG.II.size() == 1); ASSERT_TRUE(s1.MGs[0].II.empty());
ASSERT_TRUE(s1.MG.II[0] == s0.MG.II.back());
// mixRing and II are not serialized, they are meant to be reconstructed // mixRing and II are not serialized, they are meant to be reconstructed
ASSERT_TRUE(s1.mixRing.size() == 0); ASSERT_TRUE(s1.mixRing.size() == 0);