From 9b1afe5f2d488c64e3fb5e087055cf66d2165391 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Fri, 13 May 2016 20:45:20 +0100 Subject: ringct: import of Shen Noether's ring confidential transactions --- src/ringct/rctSigs.cpp | 533 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 533 insertions(+) create mode 100644 src/ringct/rctSigs.cpp (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp new file mode 100644 index 000000000..d26678165 --- /dev/null +++ b/src/ringct/rctSigs.cpp @@ -0,0 +1,533 @@ +// Copyright (c) 2016, Monero Research Labs +// +// Author: Shen Noether +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "rctSigs.h" +using namespace crypto; +using namespace std; + +namespace rct { + + //Schnorr Non-linkable + //Gen Gives a signature (L1, s1, s2) proving that the sender knows "x" such that xG = one of P1 or P2 + //Ver Verifies that signer knows an "x" such that xG = one of P1 or P2 + //These are called in the below ASNL sig generation + + void GenSchnorrNonLinkable(key & L1, key & s1, key & s2, const key & x, const key & P1, const key & P2, int index) { + key c1, c2, L2; + key a = skGen(); + if (index == 0) { + scalarmultBase(L1, a); + hash_to_scalar(c2, L1); + skGen(s2); + addKeys2(L2, s2, c2, P2); + hash_to_scalar(c1, L2); + sc_mulsub(s1.bytes, x.bytes, c1.bytes, a.bytes); + } + if (index == 1) { + scalarmultBase(L2, a); + skGen(s1); + hash_to_scalar(c1, L2); + addKeys2(L1, s1, c1, P1); + hash_to_scalar(c2, L1); + sc_mulsub(s2.bytes, x.bytes, c2.bytes, a.bytes); + } + } + + //Schnorr Non-linkable + //Gen Gives a signature (L1, s1, s2) proving that the sender knows "x" such that xG = one of P1 or P2 + //Ver Verifies that signer knows an "x" such that xG = one of P1 or P2 + //These are called in the below ASNL sig generation + bool VerSchnorrNonLinkable(const key & P1, const key & P2, const key & L1, const key & s1, const key & s2) { + key c2, L2, c1, L1p; + hash_to_scalar(c2, L1); + addKeys2(L2, s2, c2, P2); + hash_to_scalar(c1, L2); + addKeys2(L1p, s1, c1, P1); + + return equalKeys(L1, L1p); + } + + //Aggregate Schnorr Non-linkable Ring Signature (ASNL) + // c.f. http://eprint.iacr.org/2015/1098 section 5. + // These are used in range proofs (alternatively Borromean could be used) + // Gen gives a signature which proves the signer knows, for each i, + // an x[i] such that x[i]G = one of P1[i] or P2[i] + // Ver Verifies the signer knows a key for one of P1[i], P2[i] at each i + asnlSig GenASNL(key64 x, key64 P1, key64 P2, bits indices) { + DP("Generating Aggregate Schnorr Non-linkable Ring Signature\n"); + key64 s1; + int j = 0; + asnlSig rv; + rv.s = zero(); + for (j = 0; j < ATOMS; j++) { + //void GenSchnorrNonLinkable(Bytes L1, Bytes s1, Bytes s2, const Bytes x, const Bytes P1,const Bytes P2, int index) { + GenSchnorrNonLinkable(rv.L1[j], s1[j], rv.s2[j], x[j], P1[j], P2[j], (int)indices[j]); + sc_add(rv.s.bytes, rv.s.bytes, s1[j].bytes); + } + return rv; + } + + //Aggregate Schnorr Non-linkable Ring Signature (ASNL) + // c.f. http://eprint.iacr.org/2015/1098 section 5. + // These are used in range proofs (alternatively Borromean could be used) + // Gen gives a signature which proves the signer knows, for each i, + // an x[i] such that x[i]G = one of P1[i] or P2[i] + // Ver Verifies the signer knows a key for one of P1[i], P2[i] at each i + bool VerASNL(key64 P1, key64 P2, asnlSig &as) { + DP("Verifying Aggregate Schnorr Non-linkable Ring Signature\n"); + key LHS = identity(); + key RHS = scalarmultBase(as.s); + key c2, L2, c1; + int j = 0; + for (j = 0; j < ATOMS; j++) { + hash_to_scalar(c2, as.L1[j]); + addKeys2(L2, as.s2[j], c2, P2[j]); + addKeys(LHS, LHS, as.L1[j]); + hash_to_scalar(c1, L2); + addKeys(RHS, RHS, scalarmultKey(P1[j], c1)); + } + key cc; + sc_sub(cc.bytes, LHS.bytes, RHS.bytes); + DP(cc); + return sc_isnonzero(cc.bytes) == 0; + } + + //Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures) + //These are aka MG signatutes in earlier drafts of the ring ct paper + // c.f. http://eprint.iacr.org/2015/1098 section 2. + // keyImageV just does I[i] = xx[i] * Hash(xx[i] * G) for each i + // 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 + keyV keyImageV(const keyV &xx) { + keyV II(xx.size()); + size_t i = 0; + for (i = 0; i < xx.size(); i++) { + II[i] = scalarmultKey(hashToPoint(scalarmultBase(xx[i])), xx[i]); + } + return II; + } + + + //Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures) + //This is a just slghtly more efficient version than the ones described below + //(will be explained in more detail in Ring Multisig paper + //These are aka MG signatutes in earlier drafts of the ring ct paper + // c.f. http://eprint.iacr.org/2015/1098 section 2. + // keyImageV just does I[i] = xx[i] * Hash(xx[i] * G) for each i + // 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 int index) { + mgSig rv; + int rows = pk[0].size(); + int cols = pk.size(); + if (cols < 2) { + printf("Error! What is c if cols = 1!"); + } + int i = 0, j = 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); + keyV alpha(rows); + keyV aG(rows); + keyV aHP(rows); + key m2hash; + unsigned char m2[128]; + memcpy(m2, message.bytes, 32); + DP("here1"); + for (i = 0; i < rows; i++) { + skpkGen(alpha[i], aG[i]); //need to save alphas for later.. + Hi = hashToPoint(pk[index][i]); + aHP[i] = scalarmultKey(Hi, alpha[i]); + memcpy(m2+32, pk[index][i].bytes, 32); + memcpy(m2 + 64, aG[i].bytes, 32); + memcpy(m2 + 96, aHP[i].bytes, 32); + rv.II[i] = scalarmultKey(Hi, xx[i]); + precomp(Ip[i].k, rv.II[i]); + m2hash = hash_to_scalar128(m2); + sc_add(c_old.bytes, c_old.bytes, m2hash.bytes); + } + + i = (index + 1) % cols; + if (i == 0) { + copy(rv.cc, c_old); + } + while (i != index) { + + rv.ss[i] = skvGen(rows); + sc_0(c.bytes); + for (j = 0; j < rows; 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); + memcpy(m2+32, pk[i][j].bytes, 32); + memcpy(m2 + 64, L.bytes, 32); + memcpy(m2 + 96, R.bytes, 32); + m2hash = hash_to_scalar128(m2); + sc_add(c.bytes, c.bytes, m2hash.bytes); + } + copy(c_old, c); + i = (i + 1) % cols; + + if (i == 0) { + copy(rv.cc, c_old); + } + } + for (j = 0; j < rows; j++) { + sc_mulsub(rv.ss[index][j].bytes, c.bytes, xx[j].bytes, alpha[j].bytes); + } + return rv; + } + + //Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures) + //This is a just slghtly more efficient version than the ones described below + //(will be explained in more detail in Ring Multisig paper + //These are aka MG signatutes in earlier drafts of the ring ct paper + // c.f. http://eprint.iacr.org/2015/1098 section 2. + // keyImageV just does I[i] = xx[i] * Hash(xx[i] * G) for each i + // 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, keyM & pk, mgSig & rv) { + + int rows = pk[0].size(); + int cols = pk.size(); + if (cols < 2) { + printf("Error! What is c if cols = 1!"); + } + int i = 0, j = 0; + key c, L, R, Hi; + key c_old = copy(rv.cc); + vector Ip(rows); + for (i= 0 ; i< rows ; i++) { + precomp(Ip[i].k, rv.II[i]); + } + unsigned char m2[128]; + memcpy(m2, message.bytes, 32); + + key m2hash; + i = 0; + while (i < cols) { + sc_0(c.bytes); + for (j = 0; j < rows; 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); + memcpy(m2 + 32, pk[i][j].bytes, 32); + memcpy(m2 + 64, L.bytes, 32); + memcpy(m2 + 96, R.bytes, 32); + m2hash = hash_to_scalar128(m2); + sc_add(c.bytes, c.bytes, m2hash.bytes); + } + copy(c_old, c); + i = (i + 1); + } + DP("c0"); + DP(rv.cc); + DP("c_old"); + DP(c_old); + sc_sub(c.bytes, c_old.bytes, rv.cc.bytes); + return sc_isnonzero(c.bytes) == 0; + } + + + + //proveRange and verRange + //proveRange gives C, and mask such that \sumCi = C + // c.f. http://eprint.iacr.org/2015/1098 section 5.1 + // and Ci is a commitment to either 0 or 2^i, i=0,...,63 + // thus this proves that "amount" is in [0, 2^64] + // mask is a such that C = aG + bH, and b = amount + //verRange verifies that \sum Ci = C and that each Ci is a commitment to 0 or 2^i + rangeSig proveRange(key & C, key & mask, const xmr_amount & amount) { + sc_0(mask.bytes); + identity(C); + bits b; + d2b(b, amount); + rangeSig sig; + key64 ai; + key64 CiH; + int i = 0; + for (i = 0; i < ATOMS; i++) { + sc_0(ai[i].bytes); + if (b[i] == 0) { + scalarmultBase(sig.Ci[i], ai[i]); + } + if (b[i] == 1) { + addKeys1(sig.Ci[i], ai[i], H2[i]); + } + subKeys(CiH[i], sig.Ci[i], H2[i]); + sc_add(mask.bytes, mask.bytes, ai[i].bytes); + addKeys(C, C, sig.Ci[i]); + } + sig.asig = GenASNL(ai, sig.Ci, CiH, b); + return sig; + } + + //proveRange and verRange + //proveRange gives C, and mask such that \sumCi = C + // c.f. http://eprint.iacr.org/2015/1098 section 5.1 + // and Ci is a commitment to either 0 or 2^i, i=0,...,63 + // thus this proves that "amount" is in [0, 2^64] + // mask is a such that C = aG + bH, and b = amount + //verRange verifies that \sum Ci = C and that each Ci is a commitment to 0 or 2^i + bool verRange(key & C, rangeSig & as) { + key64 CiH; + int i = 0; + key Ctmp = identity(); + for (i = 0; i < 64; i++) { + subKeys(CiH[i], as.Ci[i], H2[i]); + addKeys(Ctmp, Ctmp, as.Ci[i]); + } + bool reb = equalKeys(C, Ctmp); + DP("is sum Ci = C:"); + DP(reb); + bool rab = VerASNL(as.Ci, CiH, as.asig); + DP("Is in range?"); + DP(rab); + return (reb && rab); + } + + //Ring-ct MG sigs + //Prove: + // c.f. http://eprint.iacr.org/2015/1098 section 4. definition 10. + // This does the MG sig on the "dest" part of the given key matrix, and + // the last row is the sum of input commitments from that column - sum output commitments + // this shows that sum inputs = sum outputs + //Ver: + // verifies the above sig is created corretly + mgSig proveRctMG(const ctkeyM & pubs, const ctkeyV & inSk, const ctkeyV &outSk, const ctkeyV & outPk, int index) { + mgSig mg; + //setup vars + int rows = pubs[0].size(); + int cols = pubs.size(); + keyV sk(rows + 1); + keyV tmp(rows + 1); + int i = 0, j = 0; + for (i = 0; i < rows + 1; i++) { + sc_0(sk[i].bytes); + identity(tmp[i]); + } + keyM M(cols, tmp); + //create the matrix to mg sig + for (i = 0; i < cols; i++) { + M[i][rows] = identity(); + for (j = 0; j < rows; j++) { + M[i][j] = pubs[i][j].dest; + addKeys(M[i][rows], M[i][rows], pubs[i][j].mask); + } + } + sc_0(sk[rows].bytes); + for (j = 0; j < rows; j++) { + sk[j] = copy(inSk[j].dest); + sc_add(sk[rows].bytes, sk[rows].bytes, inSk[j].mask.bytes); + } + for (i = 0; i < cols; i++) { + for (size_t j = 0; j < outPk.size(); j++) { + subKeys(M[i][rows], M[i][rows], outPk[j].mask); + } + } + for (size_t j = 0; j < outPk.size(); j++) { + sc_sub(sk[rows].bytes, sk[rows].bytes, outSk[j].mask.bytes); + } + key message = cn_fast_hash(outPk); + return MLSAG_Gen(message, M, sk, index); + } + + + //Ring-ct MG sigs + //Prove: + // c.f. http://eprint.iacr.org/2015/1098 section 4. definition 10. + // This does the MG sig on the "dest" part of the given key matrix, and + // the last row is the sum of input commitments from that column - sum output commitments + // this shows that sum inputs = sum outputs + //Ver: + // verifies the above sig is created corretly + bool verRctMG(mgSig mg, ctkeyM & pubs, ctkeyV & outPk) { + //setup vars + int rows = pubs[0].size(); + int cols = pubs.size(); + keyV tmp(rows + 1); + int i = 0, j = 0; + for (i = 0; i < rows + 1; i++) { + identity(tmp[i]); + } + keyM M(cols, tmp); + + //create the matrix to mg sig + for (j = 0; j < rows; j++) { + for (i = 0; i < cols; i++) { + M[i][j] = pubs[i][j].dest; + addKeys(M[i][rows], M[i][rows], pubs[i][j].mask); + } + } + for (size_t j = 0; j < outPk.size(); j++) { + for (i = 0; i < cols; i++) { + subKeys(M[i][rows], M[i][rows], outPk[j].mask); + } + + } + key message = cn_fast_hash(outPk); + DP("message:"); + DP(message); + return MLSAG_Ver(message, M, mg); + + } + + //These functions get keys from blockchain + //replace these when connecting blockchain + //getKeyFromBlockchain grabs a key from the blockchain at "reference_index" to mix with + //populateFromBlockchain creates a keymatrix with "mixin" columns and one of the columns is inPk + // the return value are the key matrix, and the index where inPk was put (random). + void getKeyFromBlockchain(ctkey & a, size_t reference_index) { + a.mask = pkGen(); + a.dest = pkGen(); + } + + //These functions get keys from blockchain + //replace these when connecting blockchain + //getKeyFromBlockchain grabs a key from the blockchain at "reference_index" to mix with + //populateFromBlockchain creates a keymatrix with "mixin" columns and one of the columns is inPk + // the return value are the key matrix, and the index where inPk was put (random). + tuple populateFromBlockchain(ctkeyV inPk, int mixin) { + int rows = inPk.size(); + ctkeyM rv(mixin, inPk); + int index = randXmrAmount(mixin); + int i = 0, j = 0; + for (i = 0; i < mixin; i++) { + if (i != index) { + for (j = 0; j < rows; j++) { + getKeyFromBlockchain(rv[i][j], (size_t)randXmrAmount); + } + } + } + return make_tuple(rv, index); + } + + //RingCT protocol + //genRct: + // creates an rctSig with all data necessary to verify the rangeProofs and that the signer owns one of the + // columns that are claimed as inputs, and that the sum of inputs = sum of outputs. + // Also contains masked "amount" and "mask" so the receiver can see how much they received + //verRct: + // verifies that all signatures (rangeProogs, MG sig, sum inputs = outputs) are correct + //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 + // must know the destination private key to find the correct amount, else will return a random number + rctSig genRct(ctkeyV & inSk, ctkeyV & inPk, const keyV & destinations, const vector amounts, const int mixin) { + rctSig rv; + rv.outPk.resize(destinations.size()); + rv.rangeSigs.resize(destinations.size()); + rv.ecdhInfo.resize(destinations.size()); + + size_t i = 0; + keyV masks(destinations.size()); //sk mask.. + ctkeyV outSk(destinations.size()); + for (i = 0; i < destinations.size(); i++) { + //add destination to sig + rv.outPk[i].dest = copy(destinations[i]); + //compute range proof + rv.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, amounts[i]); + #ifdef DBG + verRange(rv.outPk[i].mask, rv.rangeSigs[i]); + #endif + + //mask amount and mask + rv.ecdhInfo[i].mask = copy(outSk[i].mask); + rv.ecdhInfo[i].amount = d2h(amounts[i]); + ecdhEncode(rv.ecdhInfo[i], destinations[i]); + + } + + int index; + tie(rv.mixRing, index) = populateFromBlockchain(inPk, mixin); + rv.MG = proveRctMG(rv.mixRing, inSk, outSk, rv.outPk, index); + return rv; + } + + //RingCT protocol + //genRct: + // creates an rctSig with all data necessary to verify the rangeProofs and that the signer owns one of the + // columns that are claimed as inputs, and that the sum of inputs = sum of outputs. + // Also contains masked "amount" and "mask" so the receiver can see how much they received + //verRct: + // verifies that all signatures (rangeProogs, MG sig, sum inputs = outputs) are correct + //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 + // must know the destination private key to find the correct amount, else will return a random number + bool verRct(rctSig & rv) { + size_t i = 0; + bool rvb = true; + bool tmp; + DP("range proofs verified?"); + for (i = 0; i < rv.outPk.size(); i++) { + tmp = verRange(rv.outPk[i].mask, rv.rangeSigs[i]); + DP(tmp); + rvb = (rvb && tmp); + } + bool mgVerd = verRctMG(rv.MG, rv.mixRing, rv.outPk); + DP("mg sig verified?"); + DP(mgVerd); + + return (rvb && mgVerd); + } + + //RingCT protocol + //genRct: + // creates an rctSig with all data necessary to verify the rangeProofs and that the signer owns one of the + // columns that are claimed as inputs, and that the sum of inputs = sum of outputs. + // Also contains masked "amount" and "mask" so the receiver can see how much they received + //verRct: + // verifies that all signatures (rangeProogs, MG sig, sum inputs = outputs) are correct + //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 + // must know the destination private key to find the correct amount, else will return a random number + xmr_amount decodeRct(rctSig & rv, key & sk, int i) { + //mask amount and mask + ecdhDecode(rv.ecdhInfo[i], sk); + key mask = rv.ecdhInfo[i].mask; + key amount = rv.ecdhInfo[i].amount; + key C = rv.outPk[i].mask; + DP("C"); + DP(C); + key Ctmp; + addKeys2(Ctmp, mask, amount, H); + DP("Ctmp"); + DP(Ctmp); + if (equalKeys(C, Ctmp) == false) { + printf("warning, amount decoded incorrectly, will be unable to spend"); + } + return h2d(amount); + } + +} -- cgit v1.2.3 From 4d7f073491c5288f4fa736bb4eb573a6d386baad Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 14 May 2016 21:58:31 +0100 Subject: ringct: add simple input validation Throw when inputs aren't the expected size. --- src/ringct/rctSigs.cpp | 92 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 67 insertions(+), 25 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index d26678165..be541d6f0 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -28,6 +28,7 @@ // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include "misc_log_ex.h" #include "rctSigs.h" using namespace crypto; using namespace std; @@ -50,7 +51,7 @@ namespace rct { hash_to_scalar(c1, L2); sc_mulsub(s1.bytes, x.bytes, c1.bytes, a.bytes); } - if (index == 1) { + else if (index == 1) { scalarmultBase(L2, a); skGen(s1); hash_to_scalar(c1, L2); @@ -58,6 +59,9 @@ namespace rct { hash_to_scalar(c2, L1); sc_mulsub(s2.bytes, x.bytes, c2.bytes, a.bytes); } + else { + throw std::runtime_error("GenSchnorrNonLinkable: invalid index (should be 0 or 1)"); + } } //Schnorr Non-linkable @@ -100,7 +104,7 @@ namespace rct { // Gen gives a signature which proves the signer knows, for each i, // an x[i] such that x[i]G = one of P1[i] or P2[i] // Ver Verifies the signer knows a key for one of P1[i], P2[i] at each i - bool VerASNL(key64 P1, key64 P2, asnlSig &as) { + bool VerASNL(const key64 P1, const key64 P2, const asnlSig &as) { DP("Verifying Aggregate Schnorr Non-linkable Ring Signature\n"); key LHS = identity(); key RHS = scalarmultBase(as.s); @@ -145,14 +149,19 @@ 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 int index) { + mgSig MLSAG_Gen(key message, const keyM & pk, const keyV & xx, const unsigned int index) { mgSig rv; - int rows = pk[0].size(); - int cols = pk.size(); - if (cols < 2) { - printf("Error! What is c if cols = 1!"); + size_t cols = pk.size(); + CHECK_AND_ASSERT_THROW_MES(cols >= 2, "Error! What is c if cols = 1!"); + CHECK_AND_ASSERT_THROW_MES(index < cols, "Index out of range"); + size_t rows = pk[0].size(); + CHECK_AND_ASSERT_THROW_MES(rows >= 1, "Empty pk"); + for (size_t i = 1; i < cols; ++i) { + CHECK_AND_ASSERT_THROW_MES(pk[i].size() == rows, "pk is not rectangular"); } - int i = 0, j = 0; + CHECK_AND_ASSERT_THROW_MES(xx.size() == rows, "Bad xx size"); + + size_t i = 0, j = 0; key c, c_old, L, R, Hi; sc_0(c_old.bytes); vector Ip(rows); @@ -218,14 +227,22 @@ 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, keyM & pk, mgSig & rv) { + bool MLSAG_Ver(key message, const keyM & pk, const mgSig & rv) { - int rows = pk[0].size(); - int cols = pk.size(); - if (cols < 2) { - printf("Error! What is c if cols = 1!"); + size_t cols = pk.size(); + CHECK_AND_ASSERT_THROW_MES(cols >= 2, "Error! What is c if cols = 1!"); + size_t rows = pk[0].size(); + CHECK_AND_ASSERT_THROW_MES(rows >= 1, "Empty pk"); + for (size_t i = 1; i < cols; ++i) { + CHECK_AND_ASSERT_THROW_MES(pk[i].size() == rows, "pk is not rectangular"); } - int i = 0, j = 0; + CHECK_AND_ASSERT_THROW_MES(rv.II.size() == rows, "Bad rv.II size"); + CHECK_AND_ASSERT_THROW_MES(rv.ss.size() == cols, "Bad rv.ss size"); + for (size_t i = 0; i < cols; ++i) { + CHECK_AND_ASSERT_THROW_MES(rv.ss[i].size() == rows, "rv.ss is not rectangular"); + } + + size_t i = 0, j = 0; key c, L, R, Hi; key c_old = copy(rv.cc); vector Ip(rows); @@ -301,7 +318,7 @@ namespace rct { // thus this proves that "amount" is in [0, 2^64] // mask is a such that C = aG + bH, and b = amount //verRange verifies that \sum Ci = C and that each Ci is a commitment to 0 or 2^i - bool verRange(key & C, rangeSig & as) { + bool verRange(const key & C, const rangeSig & as) { key64 CiH; int i = 0; key Ctmp = identity(); @@ -326,14 +343,22 @@ namespace rct { // this shows that sum inputs = sum outputs //Ver: // verifies the above sig is created corretly - mgSig proveRctMG(const ctkeyM & pubs, const ctkeyV & inSk, const ctkeyV &outSk, const ctkeyV & outPk, int index) { + mgSig proveRctMG(const ctkeyM & pubs, const ctkeyV & inSk, const ctkeyV &outSk, const ctkeyV & outPk, unsigned int index) { mgSig mg; //setup vars - int rows = pubs[0].size(); - int cols = pubs.size(); + size_t cols = pubs.size(); + CHECK_AND_ASSERT_THROW_MES(cols >= 1, "Empty pubs"); + size_t rows = pubs[0].size(); + CHECK_AND_ASSERT_THROW_MES(rows >= 1, "Empty pubs"); + for (size_t i = 1; i < cols; ++i) { + CHECK_AND_ASSERT_THROW_MES(pubs[i].size() == rows, "pubs is not rectangular"); + } + CHECK_AND_ASSERT_THROW_MES(inSk.size() == rows, "Bad inSk size"); + CHECK_AND_ASSERT_THROW_MES(outSk.size() == outPk.size(), "Bad outSk/outPk size"); + keyV sk(rows + 1); keyV tmp(rows + 1); - int i = 0, j = 0; + size_t i = 0, j = 0; for (i = 0; i < rows + 1; i++) { sc_0(sk[i].bytes); identity(tmp[i]); @@ -373,12 +398,18 @@ namespace rct { // this shows that sum inputs = sum outputs //Ver: // verifies the above sig is created corretly - bool verRctMG(mgSig mg, ctkeyM & pubs, ctkeyV & outPk) { + bool verRctMG(mgSig mg, const ctkeyM & pubs, const ctkeyV & outPk) { //setup vars - int rows = pubs[0].size(); - int cols = pubs.size(); + size_t cols = pubs.size(); + CHECK_AND_ASSERT_THROW_MES(cols >= 1, "Empty pubs"); + size_t rows = pubs[0].size(); + CHECK_AND_ASSERT_THROW_MES(rows >= 1, "Empty pubs"); + for (size_t i = 1; i < cols; ++i) { + CHECK_AND_ASSERT_THROW_MES(pubs[i].size() == rows, "pubs is not rectangular"); + } + keyV tmp(rows + 1); - int i = 0, j = 0; + size_t i = 0, j = 0; for (i = 0; i < rows + 1; i++) { identity(tmp[i]); } @@ -445,6 +476,10 @@ namespace rct { // 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 rctSig genRct(ctkeyV & inSk, ctkeyV & inPk, const keyV & destinations, const vector amounts, const int mixin) { + CHECK_AND_ASSERT_THROW_MES(mixin >= 0, "Mixin must be positive"); + CHECK_AND_ASSERT_THROW_MES(amounts.size() > 0, "Amounts must not be empty"); + CHECK_AND_ASSERT_THROW_MES(inSk.size() == inPk.size(), "Different number of public/private keys"); + rctSig rv; rv.outPk.resize(destinations.size()); rv.rangeSigs.resize(destinations.size()); @@ -469,7 +504,7 @@ namespace rct { } - int index; + unsigned int index; tie(rv.mixRing, index) = populateFromBlockchain(inPk, mixin); rv.MG = proveRctMG(rv.mixRing, inSk, outSk, rv.outPk, index); return rv; @@ -486,6 +521,9 @@ namespace rct { // 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 bool verRct(rctSig & rv) { + 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"); + size_t i = 0; bool rvb = true; bool tmp; @@ -512,7 +550,11 @@ namespace rct { //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 // must know the destination private key to find the correct amount, else will return a random number - xmr_amount decodeRct(rctSig & rv, key & sk, int i) { + xmr_amount decodeRct(rctSig & rv, key & sk, unsigned int i) { + 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(i < rv.ecdhInfo.size(), "Bad index"); + //mask amount and mask ecdhDecode(rv.ecdhInfo[i], sk); key mask = rv.ecdhInfo[i].mask; -- cgit v1.2.3 From d37c1db032defacc096af4337b3c95a74e8f88be Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 28 May 2016 11:34:32 +0100 Subject: ringct: add a few consts where appropriate --- src/ringct/rctSigs.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index be541d6f0..1efb8c4f4 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -475,7 +475,7 @@ namespace rct { //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 // must know the destination private key to find the correct amount, else will return a random number - rctSig genRct(ctkeyV & inSk, ctkeyV & inPk, const keyV & destinations, const vector amounts, const int mixin) { + rctSig genRct(const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector amounts, const int mixin) { CHECK_AND_ASSERT_THROW_MES(mixin >= 0, "Mixin must be positive"); CHECK_AND_ASSERT_THROW_MES(amounts.size() > 0, "Amounts must not be empty"); CHECK_AND_ASSERT_THROW_MES(inSk.size() == inPk.size(), "Different number of public/private keys"); @@ -520,7 +520,7 @@ namespace rct { //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 // must know the destination private key to find the correct amount, else will return a random number - bool verRct(rctSig & rv) { + bool verRct(const rctSig & rv) { 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"); @@ -550,7 +550,7 @@ namespace rct { //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 // must know the destination private key to find the correct amount, else will return a random number - xmr_amount decodeRct(rctSig & rv, key & sk, unsigned int i) { + xmr_amount decodeRct(rctSig & rv, const key & sk, unsigned int i) { 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(i < rv.ecdhInfo.size(), "Bad index"); -- cgit v1.2.3 From 09fb9f4b75d29e1211f62038c794e6c63420e05e Mon Sep 17 00:00:00 2001 From: Shen Noether Date: Sun, 29 May 2016 18:34:43 -0600 Subject: Fix sc_0 to skGen in ProveRange --- src/ringct/rctSigs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 1efb8c4f4..06b93590a 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -296,7 +296,7 @@ namespace rct { key64 CiH; int i = 0; for (i = 0; i < ATOMS; i++) { - sc_0(ai[i].bytes); + skGen(ai[i]); if (b[i] == 0) { scalarmultBase(sig.Ci[i], ai[i]); } -- cgit v1.2.3 From 56f654996201f5c03f73412ed2d2f0df332a20ab Mon Sep 17 00:00:00 2001 From: Shen Noether Date: Thu, 2 Jun 2016 19:03:35 +0100 Subject: ringct: cosmetic fixes Ported from Shen's RingCT repo --- src/ringct/rctSigs.cpp | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 06b93590a..e78bec586 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -49,12 +49,13 @@ namespace rct { skGen(s2); addKeys2(L2, s2, c2, P2); hash_to_scalar(c1, L2); + //s1 = a - x * c1 sc_mulsub(s1.bytes, x.bytes, c1.bytes, a.bytes); } else if (index == 1) { scalarmultBase(L2, a); - skGen(s1); hash_to_scalar(c1, L2); + skGen(s1); addKeys2(L1, s1, c1, P1); hash_to_scalar(c2, L1); sc_mulsub(s2.bytes, x.bytes, c2.bytes, a.bytes); @@ -91,7 +92,6 @@ namespace rct { asnlSig rv; rv.s = zero(); for (j = 0; j < ATOMS; j++) { - //void GenSchnorrNonLinkable(Bytes L1, Bytes s1, Bytes s2, const Bytes x, const Bytes P1,const Bytes P2, int index) { GenSchnorrNonLinkable(rv.L1[j], s1[j], rv.s2[j], x[j], P1[j], P2[j], (int)indices[j]); sc_add(rv.s.bytes, rv.s.bytes, s1[j].bytes); } @@ -119,7 +119,6 @@ namespace rct { } key cc; sc_sub(cc.bytes, LHS.bytes, RHS.bytes); - DP(cc); return sc_isnonzero(cc.bytes) == 0; } @@ -269,10 +268,6 @@ namespace rct { copy(c_old, c); i = (i + 1); } - DP("c0"); - DP(rv.cc); - DP("c_old"); - DP(c_old); sc_sub(c.bytes, c_old.bytes, rv.cc.bytes); return sc_isnonzero(c.bytes) == 0; } @@ -327,11 +322,7 @@ namespace rct { addKeys(Ctmp, Ctmp, as.Ci[i]); } bool reb = equalKeys(C, Ctmp); - DP("is sum Ci = C:"); - DP(reb); bool rab = VerASNL(as.Ci, CiH, as.asig); - DP("Is in range?"); - DP(rab); return (reb && rab); } @@ -369,21 +360,21 @@ namespace rct { M[i][rows] = identity(); for (j = 0; j < rows; j++) { M[i][j] = pubs[i][j].dest; - addKeys(M[i][rows], M[i][rows], pubs[i][j].mask); + addKeys(M[i][rows], M[i][rows], pubs[i][j].mask); //add input commitments in last row } } sc_0(sk[rows].bytes); for (j = 0; j < rows; j++) { sk[j] = copy(inSk[j].dest); - sc_add(sk[rows].bytes, sk[rows].bytes, inSk[j].mask.bytes); + sc_add(sk[rows].bytes, sk[rows].bytes, inSk[j].mask.bytes); //add masks in last row } for (i = 0; i < cols; i++) { for (size_t j = 0; j < outPk.size(); j++) { - subKeys(M[i][rows], M[i][rows], outPk[j].mask); + subKeys(M[i][rows], M[i][rows], outPk[j].mask); //subtract output Ci's in last row } } for (size_t j = 0; j < outPk.size(); j++) { - sc_sub(sk[rows].bytes, sk[rows].bytes, outSk[j].mask.bytes); + sc_sub(sk[rows].bytes, sk[rows].bytes, outSk[j].mask.bytes); //subtract output masks in last row.. } key message = cn_fast_hash(outPk); return MLSAG_Gen(message, M, sk, index); -- cgit v1.2.3 From e816a092928d06cffe65c23f447c7ab378858343 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 4 Jun 2016 09:37:38 +0100 Subject: ringct: fix off by 1 in mixin usage --- src/ringct/rctSigs.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index e78bec586..351b615d9 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -439,14 +439,14 @@ namespace rct { //These functions get keys from blockchain //replace these when connecting blockchain //getKeyFromBlockchain grabs a key from the blockchain at "reference_index" to mix with - //populateFromBlockchain creates a keymatrix with "mixin" columns and one of the columns is inPk + //populateFromBlockchain creates a keymatrix with "mixin" + 1 columns and one of the columns is inPk // the return value are the key matrix, and the index where inPk was put (random). tuple populateFromBlockchain(ctkeyV inPk, int mixin) { int rows = inPk.size(); - ctkeyM rv(mixin, inPk); + ctkeyM rv(mixin + 1, inPk); int index = randXmrAmount(mixin); int i = 0, j = 0; - for (i = 0; i < mixin; i++) { + for (i = 0; i <= mixin; i++) { if (i != index) { for (j = 0; j < rows; j++) { getKeyFromBlockchain(rv[i][j], (size_t)randXmrAmount); -- cgit v1.2.3 From 63856cad29b87348db04102190de5d1d45d03a7e Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 4 Jun 2016 09:38:12 +0100 Subject: ringct: add check for destinations/amount size being equal --- src/ringct/rctSigs.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 351b615d9..9e2fa8cd6 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -470,6 +470,7 @@ namespace rct { CHECK_AND_ASSERT_THROW_MES(mixin >= 0, "Mixin must be positive"); CHECK_AND_ASSERT_THROW_MES(amounts.size() > 0, "Amounts must not be empty"); CHECK_AND_ASSERT_THROW_MES(inSk.size() == inPk.size(), "Different number of public/private keys"); + CHECK_AND_ASSERT_THROW_MES(amounts.size() == destinations.size(), "Different number of amounts/destinations"); rctSig rv; rv.outPk.resize(destinations.size()); -- cgit v1.2.3 From 82072e701ad319dcd4db610ffdb68c8aec0f648b Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 4 Jun 2016 09:38:36 +0100 Subject: ringct: restore verRange check in debug mode --- src/ringct/rctSigs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 9e2fa8cd6..0d0fccd63 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -486,7 +486,7 @@ namespace rct { //compute range proof rv.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, amounts[i]); #ifdef DBG - verRange(rv.outPk[i].mask, rv.rangeSigs[i]); + CHECK_AND_ASSERT_THROW_MES(verRange(rv.outPk[i].mask, rv.rangeSigs[i]), "verRange failed on newly created proof"); #endif //mask amount and mask -- cgit v1.2.3 From 66f96260b23c07802b54c02715c7fdd577ab12f9 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 12 Jun 2016 21:13:12 +0100 Subject: ringct: new {gen,decode}Rct APIs for convenience A new version of genRct takes the mixRing as parameter, instead of the inPk. inPk are part of the mixRing, and it is cleaner to pass the mixRing data than to fetch it from the RingCT code. A new version of decodeRct also returns the mask. Also, failure to decode throws, so errors are properly detected. --- src/ringct/rctSigs.cpp | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 0d0fccd63..f1ffa2702 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -466,11 +466,13 @@ namespace rct { //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 // must know the destination private key to find the correct amount, else will return a random number - rctSig genRct(const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector amounts, const int mixin) { - CHECK_AND_ASSERT_THROW_MES(mixin >= 0, "Mixin must be positive"); + rctSig genRct(const ctkeyV & inSk, const keyV & destinations, const vector amounts, const ctkeyM &mixRing, unsigned int index) { CHECK_AND_ASSERT_THROW_MES(amounts.size() > 0, "Amounts must not be empty"); - CHECK_AND_ASSERT_THROW_MES(inSk.size() == inPk.size(), "Different number of public/private keys"); CHECK_AND_ASSERT_THROW_MES(amounts.size() == destinations.size(), "Different number of amounts/destinations"); + CHECK_AND_ASSERT_THROW_MES(index < mixRing.size(), "Bad index into mixRing"); + for (size_t n = 0; n < mixRing.size(); ++n) { + CHECK_AND_ASSERT_THROW_MES(mixRing[n].size() == inSk.size(), "Bad mixRing size"); + } rctSig rv; rv.outPk.resize(destinations.size()); @@ -496,11 +498,18 @@ namespace rct { } - unsigned int index; - tie(rv.mixRing, index) = populateFromBlockchain(inPk, mixin); + rv.mixRing = mixRing; rv.MG = proveRctMG(rv.mixRing, inSk, outSk, rv.outPk, index); + if (!verRctMG(rv.MG, rv.mixRing, rv.outPk)) { printf("proveRctMG genreated bad data\n"); } return rv; } + + rctSig genRct(const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector amounts, const int mixin) { + unsigned int index; + ctkeyM mixRing; + tie(mixRing, index) = populateFromBlockchain(inPk, mixin); + return genRct(inSk, destinations, amounts, mixRing, index); + } //RingCT protocol //genRct: @@ -542,15 +551,16 @@ namespace rct { //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 // must know the destination private key to find the correct amount, else will return a random number - xmr_amount decodeRct(rctSig & rv, const key & sk, unsigned int i) { + xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask) { 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(i < rv.ecdhInfo.size(), "Bad index"); //mask amount and mask - ecdhDecode(rv.ecdhInfo[i], sk); - key mask = rv.ecdhInfo[i].mask; - key amount = rv.ecdhInfo[i].amount; + ecdhTuple ecdh_info = rv.ecdhInfo[i]; + ecdhDecode(ecdh_info, sk); + mask = ecdh_info.mask; + key amount = ecdh_info.amount; key C = rv.outPk[i].mask; DP("C"); DP(C); @@ -559,9 +569,13 @@ namespace rct { DP("Ctmp"); DP(Ctmp); if (equalKeys(C, Ctmp) == false) { - printf("warning, amount decoded incorrectly, will be unable to spend"); + CHECK_AND_ASSERT_THROW_MES(false, "warning, amount decoded incorrectly, will be unable to spend"); } return h2d(amount); } + xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i) { + key mask; + return decodeRct(rv, sk, i, mask); + } } -- cgit v1.2.3 From f8c04ad94fff9df079b59f197a49e19478385725 Mon Sep 17 00:00:00 2001 From: Shen Noether Date: Sun, 12 Jun 2016 21:53:01 +0100 Subject: ringct: txn fee stuff --- src/ringct/rctSigs.cpp | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index f1ffa2702..53cb1ab6f 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -334,7 +334,7 @@ namespace rct { // this shows that sum inputs = sum outputs //Ver: // verifies the above sig is created corretly - mgSig proveRctMG(const ctkeyM & pubs, const ctkeyV & inSk, const ctkeyV &outSk, const ctkeyV & outPk, unsigned int index) { + mgSig proveRctMG(const ctkeyM & pubs, const ctkeyV & inSk, const ctkeyV &outSk, const ctkeyV & outPk, unsigned int index, key txnFeeKey) { mgSig mg; //setup vars size_t cols = pubs.size(); @@ -372,6 +372,8 @@ namespace rct { for (size_t j = 0; j < outPk.size(); j++) { subKeys(M[i][rows], M[i][rows], outPk[j].mask); //subtract output Ci's in last row } + //subtract txn fee output in last row + subKeys(M[i][rows], M[i][rows], txnFeeKey); } 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.. @@ -389,7 +391,7 @@ namespace rct { // this shows that sum inputs = sum outputs //Ver: // verifies the above sig is created corretly - bool verRctMG(mgSig mg, const ctkeyM & pubs, const ctkeyV & outPk) { + bool verRctMG(mgSig mg, const ctkeyM & pubs, const ctkeyV & outPk, key txnFeeKey) { //setup vars size_t cols = pubs.size(); CHECK_AND_ASSERT_THROW_MES(cols >= 1, "Empty pubs"); @@ -410,20 +412,20 @@ namespace rct { for (j = 0; j < rows; j++) { for (i = 0; i < cols; i++) { M[i][j] = pubs[i][j].dest; - addKeys(M[i][rows], M[i][rows], pubs[i][j].mask); + addKeys(M[i][rows], M[i][rows], pubs[i][j].mask); //add Ci in last row } } - for (size_t j = 0; j < outPk.size(); j++) { - for (i = 0; i < cols; i++) { - subKeys(M[i][rows], M[i][rows], outPk[j].mask); + for (i = 0; i < cols; i++) { + for (j = 0; j < outPk.size(); j++) { + subKeys(M[i][rows], M[i][rows], outPk[j].mask); //subtract output Ci's in last row } - + //subtract txn fee output in last row + subKeys(M[i][rows], M[i][rows], txnFeeKey); } key message = cn_fast_hash(outPk); DP("message:"); DP(message); return MLSAG_Ver(message, M, mg); - } //These functions get keys from blockchain @@ -466,6 +468,8 @@ namespace rct { //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 // 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 + // Thus the amounts vector will be "one" longer than the destinations vectort rctSig genRct(const ctkeyV & inSk, const keyV & destinations, const vector amounts, const ctkeyM &mixRing, unsigned int index) { CHECK_AND_ASSERT_THROW_MES(amounts.size() > 0, "Amounts must not be empty"); CHECK_AND_ASSERT_THROW_MES(amounts.size() == destinations.size(), "Different number of amounts/destinations"); @@ -498,9 +502,12 @@ namespace rct { } + //set txn fee + rv.txnFee = amounts[destinations.size()]; + key txnFeeKey = scalarmultH(d2h(rv.txnFee)); + rv.mixRing = mixRing; - rv.MG = proveRctMG(rv.mixRing, inSk, outSk, rv.outPk, index); - if (!verRctMG(rv.MG, rv.mixRing, rv.outPk)) { printf("proveRctMG genreated bad data\n"); } + rv.MG = proveRctMG(rv.mixRing, inSk, outSk, rv.outPk, index, txnFeeKey); return rv; } @@ -534,7 +541,9 @@ namespace rct { DP(tmp); rvb = (rvb && tmp); } - bool mgVerd = verRctMG(rv.MG, rv.mixRing, rv.outPk); + //compute txn fee + key txnFeeKey = scalarmultH(d2h(rv.txnFee)); + bool mgVerd = verRctMG(rv.MG, rv.mixRing, rv.outPk, txnFeeKey); DP("mg sig verified?"); DP(mgVerd); -- cgit v1.2.3 From e99904ac310d0c603dae18b8a9ad3d93bff8e249 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 12 Jun 2016 22:41:40 +0100 Subject: ringct: make fee optional --- src/ringct/rctSigs.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 53cb1ab6f..a07dbaab3 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -472,7 +472,7 @@ namespace rct { // Thus the amounts vector will be "one" longer than the destinations vectort rctSig genRct(const ctkeyV & inSk, const keyV & destinations, const vector amounts, const ctkeyM &mixRing, unsigned int index) { CHECK_AND_ASSERT_THROW_MES(amounts.size() > 0, "Amounts must not be empty"); - CHECK_AND_ASSERT_THROW_MES(amounts.size() == destinations.size(), "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"); for (size_t n = 0; n < mixRing.size(); ++n) { CHECK_AND_ASSERT_THROW_MES(mixRing[n].size() == inSk.size(), "Bad mixRing size"); @@ -503,7 +503,14 @@ namespace rct { } //set txn fee - rv.txnFee = amounts[destinations.size()]; + if (amounts.size() > destinations.size()) + { + rv.txnFee = amounts[destinations.size()]; + } + else + { + rv.txnFee = 0; + } key txnFeeKey = scalarmultH(d2h(rv.txnFee)); rv.mixRing = mixRing; -- cgit v1.2.3 From 54f7429cf62ba9c8e32cf6b2a841215b1eb5b7a0 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Tue, 14 Jun 2016 17:15:49 +0100 Subject: ringct: allow no outputs, and add tests for this and fees --- src/ringct/rctSigs.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index a07dbaab3..7b83ca0e2 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -471,7 +471,6 @@ namespace rct { // 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 rctSig genRct(const ctkeyV & inSk, const keyV & destinations, const vector amounts, const ctkeyM &mixRing, unsigned int index) { - CHECK_AND_ASSERT_THROW_MES(amounts.size() > 0, "Amounts must not be empty"); 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"); for (size_t n = 0; n < mixRing.size(); ++n) { @@ -536,7 +535,6 @@ namespace rct { // 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 bool verRct(const rctSig & rv) { - 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"); size_t i = 0; -- cgit v1.2.3 From dc4aad7eb5fffa450d4c5eb094cf962e45b2f43a Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Wed, 15 Jun 2016 23:37:13 +0100 Subject: add rct to the protocol It is not yet constrained to a fork, so don't use on the real network or you'll be orphaned or rejected. --- src/ringct/rctSigs.cpp | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 7b83ca0e2..358feeb5d 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -537,22 +537,30 @@ namespace rct { bool verRct(const rctSig & rv) { CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.rangeSigs.size(), "Mismatched sizes of rv.outPk and rv.rangeSigs"); - size_t i = 0; - bool rvb = true; - bool tmp; - DP("range proofs verified?"); - for (i = 0; i < rv.outPk.size(); i++) { - tmp = verRange(rv.outPk[i].mask, rv.rangeSigs[i]); - DP(tmp); - rvb = (rvb && tmp); - } - //compute txn fee - key txnFeeKey = scalarmultH(d2h(rv.txnFee)); - bool mgVerd = verRctMG(rv.MG, rv.mixRing, rv.outPk, txnFeeKey); - DP("mg sig verified?"); - DP(mgVerd); + // some rct ops can throw + try + { + size_t i = 0; + bool rvb = true; + bool tmp; + DP("range proofs verified?"); + for (i = 0; i < rv.outPk.size(); i++) { + tmp = verRange(rv.outPk[i].mask, rv.rangeSigs[i]); + DP(tmp); + rvb = (rvb && tmp); + } + //compute txn fee + key txnFeeKey = scalarmultH(d2h(rv.txnFee)); + bool mgVerd = verRctMG(rv.MG, rv.mixRing, rv.outPk, txnFeeKey); + DP("mg sig verified?"); + DP(mgVerd); - return (rvb && mgVerd); + return (rvb && mgVerd); + } + catch(...) + { + return false; + } } //RingCT protocol -- cgit v1.2.3 From 229968eafc8a6cb83611bfd6030196d5ca9f4b7c Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Fri, 17 Jun 2016 20:48:36 +0100 Subject: ringct: change asserts to return false for boolean functions --- src/ringct/rctSigs.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 358feeb5d..5e4d7baae 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -229,16 +229,16 @@ namespace rct { bool MLSAG_Ver(key message, const keyM & pk, const mgSig & rv) { size_t cols = pk.size(); - CHECK_AND_ASSERT_THROW_MES(cols >= 2, "Error! What is c if cols = 1!"); + CHECK_AND_ASSERT_MES(cols >= 2, false, "Error! What is c if cols = 1!"); size_t rows = pk[0].size(); - CHECK_AND_ASSERT_THROW_MES(rows >= 1, "Empty pk"); + CHECK_AND_ASSERT_MES(rows >= 1, false, "Empty pk"); for (size_t i = 1; i < cols; ++i) { - CHECK_AND_ASSERT_THROW_MES(pk[i].size() == rows, "pk is not rectangular"); + CHECK_AND_ASSERT_MES(pk[i].size() == rows, false, "pk is not rectangular"); } - CHECK_AND_ASSERT_THROW_MES(rv.II.size() == rows, "Bad rv.II size"); - CHECK_AND_ASSERT_THROW_MES(rv.ss.size() == cols, "Bad rv.ss size"); + CHECK_AND_ASSERT_MES(rv.II.size() == rows, false, "Bad rv.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_THROW_MES(rv.ss[i].size() == rows, "rv.ss is not rectangular"); + CHECK_AND_ASSERT_MES(rv.ss[i].size() == rows, false, "rv.ss is not rectangular"); } size_t i = 0, j = 0; @@ -394,11 +394,11 @@ namespace rct { bool verRctMG(mgSig mg, const ctkeyM & pubs, const ctkeyV & outPk, key txnFeeKey) { //setup vars size_t cols = pubs.size(); - CHECK_AND_ASSERT_THROW_MES(cols >= 1, "Empty pubs"); + CHECK_AND_ASSERT_MES(cols >= 1, false, "Empty pubs"); size_t rows = pubs[0].size(); - CHECK_AND_ASSERT_THROW_MES(rows >= 1, "Empty pubs"); + CHECK_AND_ASSERT_MES(rows >= 1, false, "Empty pubs"); for (size_t i = 1; i < cols; ++i) { - CHECK_AND_ASSERT_THROW_MES(pubs[i].size() == rows, "pubs is not rectangular"); + CHECK_AND_ASSERT_MES(pubs[i].size() == rows, false, "pubs is not rectangular"); } keyV tmp(rows + 1); @@ -535,7 +535,7 @@ namespace rct { // 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 bool verRct(const rctSig & rv) { - CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.rangeSigs.size(), "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"); // some rct ops can throw try -- cgit v1.2.3 From 359f46901ee5c46fe125248ccb769fe27188a61a Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Fri, 17 Jun 2016 21:28:56 +0100 Subject: ringct: add missing size check for ecdhInfo --- src/ringct/rctSigs.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 5e4d7baae..89adb2a77 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -536,6 +536,7 @@ namespace rct { // must know the destination private key to find the correct amount, else will return a random number bool verRct(const rctSig & rv) { 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"); // some rct ops can throw try -- cgit v1.2.3 From 20e50ec7f7f4104b5eb177aa30df4f5d4db9c8c3 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Wed, 29 Jun 2016 18:18:18 +0100 Subject: 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. --- src/ringct/rctSigs.cpp | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 89adb2a77..917ac54cd 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -226,7 +226,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) { + bool MLSAG_Ver(key message, const keyM & pk, const mgSig & rv, const keyV &II) { size_t cols = pk.size(); 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) { 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"); for (size_t i = 0; i < cols; ++i) { 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); vector Ip(rows); for (i= 0 ; i< rows ; i++) { - precomp(Ip[i].k, rv.II[i]); + precomp(Ip[i].k, II[i]); } unsigned char m2[128]; memcpy(m2, message.bytes, 32); @@ -334,7 +334,7 @@ namespace rct { // this shows that sum inputs = sum outputs //Ver: // 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; //setup vars size_t cols = pubs.size(); @@ -378,7 +378,9 @@ namespace rct { 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.. } - 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); } @@ -391,7 +393,7 @@ namespace rct { // this shows that sum inputs = sum outputs //Ver: // 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 size_t cols = pubs.size(); CHECK_AND_ASSERT_MES(cols >= 1, false, "Empty pubs"); @@ -422,10 +424,12 @@ namespace rct { //subtract txn fee output in last row 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); - return MLSAG_Ver(message, M, mg); + return MLSAG_Ver(message, M, mg, II); } //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 // 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 - rctSig genRct(const ctkeyV & inSk, const keyV & destinations, const vector amounts, const ctkeyM &mixRing, unsigned int index) { + rctSig genRct(const ctkeyV & inSk, const keyV & destinations, const vector 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(index < mixRing.size(), "Bad index into mixRing"); for (size_t n = 0; n < mixRing.size(); ++n) { @@ -513,15 +517,16 @@ namespace rct { key txnFeeKey = scalarmultH(d2h(rv.txnFee)); 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; } - rctSig genRct(const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector amounts, const int mixin) { + rctSig genRct(const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector amounts, const key &base_hash, const int mixin) { unsigned int index; ctkeyM mixRing; tie(mixRing, index) = populateFromBlockchain(inPk, mixin); - return genRct(inSk, destinations, amounts, mixRing, index); + return genRct(inSk, destinations, amounts, mixRing, base_hash, index); } //RingCT protocol @@ -534,7 +539,7 @@ namespace rct { //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 // 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.ecdhInfo.size(), false, "Mismatched sizes of rv.outPk and rv.ecdhInfo"); @@ -552,7 +557,7 @@ namespace rct { } //compute txn fee 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(mgVerd); @@ -563,6 +568,9 @@ namespace rct { return false; } } + bool verRct(const rctSig & rv) { + return verRct(rv, rv.mixRing, rv.MG.II, rv.base_hash); + } //RingCT protocol //genRct: -- cgit v1.2.3 From 4fd01f2bee0a64a72d67129e2f84007125e81ad2 Mon Sep 17 00:00:00 2001 From: Shen Noether Date: Sat, 9 Jul 2016 19:30:28 +0100 Subject: ringct: "simple" ringct variant Allows the fake outs to be in different positions for each ring. For rct inputs only. --- src/ringct/rctSigs.cpp | 211 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 917ac54cd..c9e34ddb6 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -385,6 +385,33 @@ namespace rct { } + //Ring-ct MG sigs Simple + // Simple version for when we assume only + // post rct inputs + // here pubs is a vector of (P, C) length mixin + // inSk is x, a_in corresponding to signing index + // a_out, Cout is for the output commitment + // index is the signing index.. + mgSig proveRctMGSimple(const key &message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, unsigned int index) { + mgSig mg; + //setup vars + size_t rows = 1; + size_t cols = pubs.size(); + CHECK_AND_ASSERT_THROW_MES(cols >= 1, "Empty pubs"); + keyV tmp(rows + 1); + keyV sk(rows + 1); + size_t i; + keyM M(cols, tmp); + for (i = 0; i < cols; i++) { + M[i][0] = pubs[i].dest; + subKeys(M[i][1], pubs[i].mask, Cout); + sk[0] = copy(inSk.dest); + sc_sub(sk[1].bytes, inSk.mask.bytes, a.bytes); + } + return MLSAG_Gen(message, M, sk, index); + } + + //Ring-ct MG sigs //Prove: // c.f. http://eprint.iacr.org/2015/1098 section 4. definition 10. @@ -432,6 +459,27 @@ namespace rct { return MLSAG_Ver(message, M, mg, II); } + //Ring-ct Simple MG sigs + //Ver: + //This does a simplified version, assuming only post Rct + //inputs + bool verRctMGSimple(const key &message, const mgSig &mg, const keyV &II, const ctkeyV & pubs, const key & C) { + //setup vars + size_t rows = 1; + size_t cols = pubs.size(); + CHECK_AND_ASSERT_MES(cols >= 1, false, "Empty pubs"); + keyV tmp(rows + 1); + size_t i; + keyM M(cols, tmp); + //create the matrix to mg sig + for (i = 0; i < cols; i++) { + M[i][0] = pubs[i].dest; + subKeys(M[i][1], pubs[i].mask, C); + } + //DP(C); + return MLSAG_Ver(message, M, mg, II); + } + //These functions get keys from blockchain //replace these when connecting blockchain //getKeyFromBlockchain grabs a key from the blockchain at "reference_index" to mix with @@ -462,6 +510,24 @@ namespace rct { return make_tuple(rv, index); } + //These functions get keys from blockchain + //replace these when connecting blockchain + //getKeyFromBlockchain grabs a key from the blockchain at "reference_index" to mix with + //populateFromBlockchain creates a keymatrix with "mixin" columns and one of the columns is inPk + // the return value are the key matrix, and the index where inPk was put (random). + xmr_amount populateFromBlockchainSimple(ctkeyV & mixRing, const ctkey & inPk, int mixin) { + int index = randXmrAmount(mixin); + int i = 0; + for (i = 0; i <= mixin; i++) { + if (i != index) { + getKeyFromBlockchain(mixRing[i], (size_t)randXmrAmount(1000)); + } else { + mixRing[i] = inPk; + } + } + return index; + } + //RingCT protocol //genRct: // creates an rctSig with all data necessary to verify the rangeProofs and that the signer owns one of the @@ -529,6 +595,82 @@ namespace rct { return genRct(inSk, destinations, amounts, mixRing, base_hash, index); } + //RCT simple + //for post-rct only + sRctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector &inamounts, const vector &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const std::vector & index) { + 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(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(mixRing.size() == inSk.size(), "Different number of mixRing/inSk"); + for (size_t n = 0; n < mixRing.size(); ++n) { + CHECK_AND_ASSERT_THROW_MES(index[n] < mixRing[n].size(), "Bad index into mixRing"); + } + + sRctSig rv; + rv.message = message; + rv.outPk.resize(destinations.size()); + rv.rangeSigs.resize(destinations.size()); + rv.ecdhInfo.resize(destinations.size()); + + size_t i; + keyV masks(destinations.size()); //sk mask.. + ctkeyV outSk(destinations.size()); + key sumout = zero(); + for (i = 0; i < destinations.size(); i++) { + + //add destination to sig + rv.outPk[i].dest = copy(destinations[i]); + //compute range proof + rv.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, outamounts[i]); + #ifdef DBG + verRange(rv.outPk[i].mask, rv.rangeSigs[i]); + #endif + + sc_add(sumout.bytes, outSk[i].mask.bytes, sumout.bytes); + + //mask amount and mask + rv.ecdhInfo[i].mask = copy(outSk[i].mask); + rv.ecdhInfo[i].amount = d2h(outamounts[i]); + ecdhEncode(rv.ecdhInfo[i], destinations[i]); + } + + //set txn fee + rv.txnFee = txnFee; +// TODO: unused ?? +// key txnFeeKey = scalarmultH(d2h(rv.txnFee)); + rv.mixRing = mixRing; + rv.pseudoOuts.resize(inamounts.size()); + rv.MG.resize(inamounts.size()); + key sumpouts = zero(); //sum pseudoOut masks + key a; + for (i = 0 ; i < inamounts.size() - 1; i++) { + skGen(a); + sc_add(sumpouts.bytes, a.bytes, sumpouts.bytes); + genC(rv.pseudoOuts[i], a, inamounts[i]); + rv.MG[i] = proveRctMGSimple(message, rv.mixRing[i], inSk[i], a, rv.pseudoOuts[i], index[i]); + } + rv.mixRing = mixRing; + sc_sub(a.bytes, sumout.bytes, sumpouts.bytes); + genC(rv.pseudoOuts[i], a, inamounts[i]); + DP(rv.pseudoOuts[i]); + rv.MG[i] = proveRctMGSimple(message, rv.mixRing[i], inSk[i], a, rv.pseudoOuts[i], index[i]); + return rv; + } + + sRctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector &inamounts, const vector &outamounts, xmr_amount txnFee, unsigned int mixin) { + std::vector index; + index.resize(inPk.size()); + ctkeyM mixRing; + mixRing.resize(inPk.size()); + for (size_t i = 0; i < inPk.size(); ++i) { + mixRing[i].resize(mixin+1); + index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin); + } + return genRctSimple(message, inSk, inPk, destinations, inamounts, outamounts, txnFee, mixRing, index); + } + //RingCT protocol //genRct: // creates an rctSig with all data necessary to verify the rangeProofs and that the signer owns one of the @@ -572,6 +714,52 @@ namespace rct { return verRct(rv, rv.mixRing, rv.MG.II, rv.base_hash); } + //ver RingCT simple + //assumes only post-rct style inputs (at least for max anonymity) + bool verRctSimple(const sRctSig & rv) { + size_t i = 0; + bool rvb = true; + + 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.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"); + + key sumOutpks = identity(); + for (i = 0; i < rv.outPk.size(); i++) { + if (!verRange(rv.outPk[i].mask, rv.rangeSigs[i])) { + return false; + } + addKeys(sumOutpks, sumOutpks, rv.outPk[i].mask); + } + DP(sumOutpks); + key txnFeeKey = scalarmultH(d2h(rv.txnFee)); + addKeys(sumOutpks, txnFeeKey, sumOutpks); + + bool tmpb = false; + key sumPseudoOuts = identity(); + for (i = 0 ; i < rv.mixRing.size() ; i++) { + tmpb = verRctMGSimple(rv.message, rv.MG[i], rv.MG[i].II, rv.mixRing[i], rv.pseudoOuts[i]); + addKeys(sumPseudoOuts, sumPseudoOuts, rv.pseudoOuts[i]); + DP(tmpb); + if (!tmpb) { + return false; + } + } + DP(sumPseudoOuts); + bool mgVerd = true; + + //check pseudoOuts vs Outs.. + if (!equalKeys(sumPseudoOuts, sumOutpks)) { + return false; + } + + DP("mg sig verified?"); + DP(mgVerd); + + return (rvb && mgVerd); + } + //RingCT protocol //genRct: // creates an rctSig with all data necessary to verify the rangeProofs and that the signer owns one of the @@ -609,4 +797,27 @@ namespace rct { key mask; return decodeRct(rv, sk, i, mask); } + + xmr_amount decodeRct(const sRctSig & rv, const key & sk, unsigned int i) { + 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(i < rv.ecdhInfo.size(), "Bad index"); + + //mask amount and mask + ecdhTuple ecdh_info = rv.ecdhInfo[i]; + ecdhDecode(ecdh_info, sk); + key mask = ecdh_info.mask; + key amount = ecdh_info.amount; + key C = rv.outPk[i].mask; + DP("C"); + DP(C); + key Ctmp; + addKeys2(Ctmp, mask, amount, H); + DP("Ctmp"); + DP(Ctmp); + if (equalKeys(C, Ctmp) == false) { + CHECK_AND_ASSERT_THROW_MES(false, "warning, amount decoded incorrectly, will be unable to spend"); + } + return h2d(amount); + } } -- cgit v1.2.3 From dbb5f2d6a3d34c0fa899fd26313873cc69dbad9d Mon Sep 17 00:00:00 2001 From: Shen Noether Date: Sat, 9 Jul 2016 20:04:23 +0100 Subject: ringct: optimization/cleanup of hash functions --- src/ringct/rctSigs.cpp | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index c9e34ddb6..7fcb8e158 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -169,22 +169,21 @@ namespace rct { keyV alpha(rows); keyV aG(rows); keyV aHP(rows); - key m2hash; - unsigned char m2[128]; - memcpy(m2, message.bytes, 32); + keyV toHash(1 + 3 * rows); + toHash[0] = message; DP("here1"); for (i = 0; i < rows; i++) { skpkGen(alpha[i], aG[i]); //need to save alphas for later.. Hi = hashToPoint(pk[index][i]); aHP[i] = scalarmultKey(Hi, alpha[i]); - memcpy(m2+32, pk[index][i].bytes, 32); - memcpy(m2 + 64, aG[i].bytes, 32); - memcpy(m2 + 96, aHP[i].bytes, 32); + toHash[3 * i + 1] = pk[index][i]; + toHash[3 * i + 2] = aG[i]; + toHash[3 * i + 3] = aHP[i]; rv.II[i] = scalarmultKey(Hi, xx[i]); precomp(Ip[i].k, rv.II[i]); - m2hash = hash_to_scalar128(m2); - sc_add(c_old.bytes, c_old.bytes, m2hash.bytes); } + c_old = hash_to_scalar(toHash); + i = (index + 1) % cols; if (i == 0) { @@ -198,12 +197,11 @@ namespace rct { 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); - memcpy(m2+32, pk[i][j].bytes, 32); - memcpy(m2 + 64, L.bytes, 32); - memcpy(m2 + 96, R.bytes, 32); - m2hash = hash_to_scalar128(m2); - sc_add(c.bytes, c.bytes, m2hash.bytes); + toHash[3 * j + 1] = pk[i][j]; + toHash[3 * j + 2] = L; + toHash[3 * j + 3] = R; } + c = hash_to_scalar(toHash); copy(c_old, c); i = (i + 1) % cols; @@ -248,10 +246,8 @@ namespace rct { for (i= 0 ; i< rows ; i++) { precomp(Ip[i].k, II[i]); } - unsigned char m2[128]; - memcpy(m2, message.bytes, 32); - - key m2hash; + keyV toHash(1 + 3 * rows); + toHash[0] = message; i = 0; while (i < cols) { sc_0(c.bytes); @@ -259,12 +255,11 @@ namespace rct { 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); - memcpy(m2 + 32, pk[i][j].bytes, 32); - memcpy(m2 + 64, L.bytes, 32); - memcpy(m2 + 96, R.bytes, 32); - m2hash = hash_to_scalar128(m2); - sc_add(c.bytes, c.bytes, m2hash.bytes); + toHash[3 * j + 1] = pk[i][j]; + toHash[3 * j + 2] = L; + toHash[3 * j + 3] = R; } + c = hash_to_scalar(toHash); copy(c_old, c); i = (i + 1); } -- cgit v1.2.3 From a4d4d6194bf9a0826806521d72a7fec5e506a677 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 10 Jul 2016 12:57:22 +0100 Subject: integrate simple rct api --- src/ringct/rctSigs.cpp | 84 +++++++++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 31 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 7fcb8e158..687373fe5 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -329,7 +329,7 @@ namespace rct { // this shows that sum inputs = sum outputs //Ver: // 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; //setup vars 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.. } 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); + signed_data.push_back(ctkey({message, identity()})); + key msg = cn_fast_hash(signed_data); + return MLSAG_Gen(msg, M, sk, index); } @@ -415,7 +415,7 @@ namespace rct { // this shows that sum inputs = sum outputs //Ver: // 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 size_t cols = pubs.size(); CHECK_AND_ASSERT_MES(cols >= 1, false, "Empty pubs"); @@ -447,11 +447,11 @@ namespace rct { subKeys(M[i][rows], M[i][rows], txnFeeKey); } ctkeyV signed_data = outPk; - signed_data.push_back(ctkey({base_hash, identity()})); - key message = cn_fast_hash(signed_data); + signed_data.push_back(ctkey({message, identity()})); + key msg = cn_fast_hash(signed_data); DP("message:"); - DP(message); - return MLSAG_Ver(message, M, mg, II); + DP(msg); + return MLSAG_Ver(msg, M, mg, II); } //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 // 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 - rctSig genRct(const ctkeyV & inSk, const keyV & destinations, const vector amounts, const ctkeyM &mixRing, const key &base_hash, unsigned int index) { + rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector & 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(index < mixRing.size(), "Bad index into mixRing"); for (size_t n = 0; n < mixRing.size(); ++n) { @@ -543,6 +543,7 @@ namespace rct { } rctSig rv; + rv.simple = false; rv.outPk.resize(destinations.size()); rv.rangeSigs.resize(destinations.size()); rv.ecdhInfo.resize(destinations.size()); @@ -578,23 +579,22 @@ namespace rct { key txnFeeKey = scalarmultH(d2h(rv.txnFee)); rv.mixRing = mixRing; - rv.base_hash = base_hash; - rv.MG = proveRctMG(rv.mixRing, inSk, outSk, rv.outPk, index, txnFeeKey, base_hash); + rv.message = message; + rv.MG = proveRctMG(message, rv.mixRing, inSk, outSk, rv.outPk, index, txnFeeKey); return rv; } - rctSig genRct(const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector amounts, const key &base_hash, const int mixin) { + rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector & amounts, const int mixin) { unsigned int index; ctkeyM mixRing; 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 //for post-rct only - sRctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector &inamounts, const vector &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const std::vector & index) { + rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector &inamounts, const vector &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const std::vector & index) { 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(outamounts.size() == destinations.size(), "Different number of amounts/destinations"); 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"); } - sRctSig rv; + rctSig rv; + rv.simple = true; rv.message = message; rv.outPk.resize(destinations.size()); rv.rangeSigs.resize(destinations.size()); @@ -637,24 +638,24 @@ namespace rct { // key txnFeeKey = scalarmultH(d2h(rv.txnFee)); rv.mixRing = mixRing; rv.pseudoOuts.resize(inamounts.size()); - rv.MG.resize(inamounts.size()); + rv.MGs.resize(inamounts.size()); key sumpouts = zero(); //sum pseudoOut masks key a; for (i = 0 ; i < inamounts.size() - 1; i++) { skGen(a); sc_add(sumpouts.bytes, a.bytes, sumpouts.bytes); 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; sc_sub(a.bytes, sumout.bytes, sumpouts.bytes); genC(rv.pseudoOuts[i], a, inamounts[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; } - sRctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector &inamounts, const vector &outamounts, xmr_amount txnFee, unsigned int mixin) { + rctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector &inamounts, const vector &outamounts, xmr_amount txnFee, unsigned int mixin) { std::vector index; index.resize(inPk.size()); ctkeyM mixRing; @@ -663,7 +664,7 @@ namespace rct { mixRing[i].resize(mixin+1); 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 @@ -676,7 +677,8 @@ namespace rct { //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 // 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.ecdhInfo.size(), false, "Mismatched sizes of rv.outPk and rv.ecdhInfo"); @@ -694,7 +696,7 @@ namespace rct { } //compute txn fee 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(mgVerd); @@ -706,19 +708,28 @@ namespace rct { } } 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 //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 *II, const key &message) { size_t i = 0; 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.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.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(); for (i = 0; i < rv.outPk.size(); i++) { @@ -733,8 +744,8 @@ namespace rct { bool tmpb = false; key sumPseudoOuts = identity(); - for (i = 0 ; i < rv.mixRing.size() ; i++) { - tmpb = verRctMGSimple(rv.message, rv.MG[i], rv.MG[i].II, rv.mixRing[i], rv.pseudoOuts[i]); + for (i = 0 ; i < mixRing.size() ; 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]); DP(tmpb); if (!tmpb) { @@ -755,6 +766,10 @@ namespace rct { return (rvb && mgVerd); } + bool verRctSimple(const rctSig & rv) { + return verRctSimple(rv, rv.mixRing, NULL, rv.message); + } + //RingCT protocol //genRct: // 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 // 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) { + 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.outPk.size() == rv.rangeSigs.size(), "Mismatched sizes of rv.outPk and rv.rangeSigs"); CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index"); @@ -793,7 +809,8 @@ namespace rct { 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.outPk.size() == rv.rangeSigs.size(), "Mismatched sizes of rv.outPk and rv.rangeSigs"); CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index"); @@ -801,7 +818,7 @@ namespace rct { //mask amount and mask ecdhTuple ecdh_info = rv.ecdhInfo[i]; ecdhDecode(ecdh_info, sk); - key mask = ecdh_info.mask; + mask = ecdh_info.mask; key amount = ecdh_info.amount; key C = rv.outPk[i].mask; DP("C"); @@ -815,4 +832,9 @@ namespace rct { } return h2d(amount); } + + xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i) { + key mask; + return decodeRctSimple(rv, sk, i, mask); + } } -- cgit v1.2.3 From e81a2b2cfabfb1ad9aaade752a863f1448fc89cd Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Mon, 11 Jul 2016 23:14:58 +0100 Subject: port get_tx_key/check_tx_key to rct --- src/ringct/rctSigs.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 687373fe5..c4a297190 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -535,7 +535,7 @@ namespace rct { // 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 // Thus the amounts vector will be "one" longer than the destinations vectort - rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector & amounts, const ctkeyM &mixRing, unsigned int index) { + rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector & amounts, const ctkeyM &mixRing, unsigned int index, ctkeyV &outSk) { 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"); for (size_t n = 0; n < mixRing.size(); ++n) { @@ -550,7 +550,7 @@ namespace rct { size_t i = 0; keyV masks(destinations.size()); //sk mask.. - ctkeyV outSk(destinations.size()); + outSk.resize(destinations.size()); for (i = 0; i < destinations.size(); i++) { //add destination to sig rv.outPk[i].dest = copy(destinations[i]); @@ -587,13 +587,14 @@ namespace rct { rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector & amounts, const int mixin) { unsigned int index; ctkeyM mixRing; + ctkeyV outSk; tie(mixRing, index) = populateFromBlockchain(inPk, mixin); - return genRct(message, inSk, destinations, amounts, mixRing, index); + return genRct(message, inSk, destinations, amounts, mixRing, index, outSk); } //RCT simple //for post-rct only - rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector &inamounts, const vector &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const std::vector & index) { + rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector &inamounts, const vector &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const std::vector & index, ctkeyV &outSk) { CHECK_AND_ASSERT_THROW_MES(inamounts.size() > 0, "Empty inamounts"); 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"); @@ -612,7 +613,7 @@ namespace rct { size_t i; keyV masks(destinations.size()); //sk mask.. - ctkeyV outSk(destinations.size()); + outSk.resize(destinations.size()); key sumout = zero(); for (i = 0; i < destinations.size(); i++) { @@ -659,12 +660,13 @@ namespace rct { std::vector index; index.resize(inPk.size()); ctkeyM mixRing; + ctkeyV outSk; mixRing.resize(inPk.size()); for (size_t i = 0; i < inPk.size(); ++i) { mixRing[i].resize(mixin+1); index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin); } - return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, index); + return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, index, outSk); } //RingCT protocol -- cgit v1.2.3 From cf33e1a52a0cf20a7cec619d85d68f000b2e1f40 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 23 Jul 2016 12:09:33 +0100 Subject: rct: do not serialize public keys in outPk They can be reconstructed from vout --- src/ringct/rctSigs.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index c4a297190..fa9c833dd 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -679,10 +679,10 @@ namespace rct { //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 // 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 &message) { + bool verRct(const rctSig & rv, const ctkeyM &mixRing, const keyV &II, const ctkeyV &outPk, 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.ecdhInfo.size(), false, "Mismatched sizes of rv.outPk and rv.ecdhInfo"); + CHECK_AND_ASSERT_MES(outPk.size() == rv.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.rangeSigs"); + CHECK_AND_ASSERT_MES(outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo"); // some rct ops can throw try @@ -691,14 +691,14 @@ namespace rct { bool rvb = true; bool tmp; DP("range proofs verified?"); - for (i = 0; i < rv.outPk.size(); i++) { - tmp = verRange(rv.outPk[i].mask, rv.rangeSigs[i]); + for (i = 0; i < outPk.size(); i++) { + tmp = verRange(outPk[i].mask, rv.rangeSigs[i]); DP(tmp); rvb = (rvb && tmp); } //compute txn fee key txnFeeKey = scalarmultH(d2h(rv.txnFee)); - bool mgVerd = verRctMG(rv.MG, II, mixRing, rv.outPk, txnFeeKey, message); + bool mgVerd = verRctMG(rv.MG, II, mixRing, outPk, txnFeeKey, message); DP("mg sig verified?"); DP(mgVerd); @@ -710,18 +710,18 @@ namespace rct { } } bool verRct(const rctSig & rv) { - return verRct(rv, rv.mixRing, rv.MG.II, rv.message); + return verRct(rv, rv.mixRing, rv.MG.II, rv.outPk, rv.message); } //ver RingCT simple //assumes only post-rct style inputs (at least for max anonymity) - bool verRctSimple(const rctSig & rv, const ctkeyM &mixRing, const std::vector *II, const key &message) { + bool verRctSimple(const rctSig & rv, const ctkeyM &mixRing, const std::vector *II, const ctkeyV &outPk, const key &message) { size_t i = 0; 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.ecdhInfo.size(), false, "Mismatched sizes of rv.outPk and rv.ecdhInfo"); + CHECK_AND_ASSERT_MES(outPk.size() == rv.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.rangeSigs"); + CHECK_AND_ASSERT_MES(outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of 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() == mixRing.size(), false, "Mismatched sizes of rv.pseudoOuts and mixRing"); CHECK_AND_ASSERT_MES(!II || II->size() == mixRing.size(), false, "Mismatched II/mixRing size"); @@ -734,11 +734,11 @@ namespace rct { } key sumOutpks = identity(); - for (i = 0; i < rv.outPk.size(); i++) { - if (!verRange(rv.outPk[i].mask, rv.rangeSigs[i])) { + for (i = 0; i < outPk.size(); i++) { + if (!verRange(outPk[i].mask, rv.rangeSigs[i])) { return false; } - addKeys(sumOutpks, sumOutpks, rv.outPk[i].mask); + addKeys(sumOutpks, sumOutpks, outPk[i].mask); } DP(sumOutpks); key txnFeeKey = scalarmultH(d2h(rv.txnFee)); @@ -769,7 +769,7 @@ namespace rct { } bool verRctSimple(const rctSig & rv) { - return verRctSimple(rv, rv.mixRing, NULL, rv.message); + return verRctSimple(rv, rv.mixRing, NULL, rv.outPk, rv.message); } //RingCT protocol -- cgit v1.2.3 From 9b70856ccb97943249f6e76b19f8abce5cd7aabe Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 24 Jul 2016 17:53:34 +0100 Subject: rct: make the amount key derivable by a third party with the tx key Scheme design from luigi1114. --- src/ringct/rctSigs.cpp | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index fa9c833dd..0d4fbee1a 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -535,7 +535,7 @@ namespace rct { // 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 // Thus the amounts vector will be "one" longer than the destinations vectort - rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector & amounts, const ctkeyM &mixRing, unsigned int index, ctkeyV &outSk) { + rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector & amounts, const ctkeyM &mixRing, const keyV &amount_keys, unsigned int index, ctkeyV &outSk) { 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"); for (size_t n = 0; n < mixRing.size(); ++n) { @@ -563,7 +563,7 @@ namespace rct { //mask amount and mask rv.ecdhInfo[i].mask = copy(outSk[i].mask); rv.ecdhInfo[i].amount = d2h(amounts[i]); - ecdhEncode(rv.ecdhInfo[i], destinations[i]); + ecdhEncodeFromSharedSecret(rv.ecdhInfo[i], amount_keys[i]); } @@ -584,17 +584,17 @@ namespace rct { return rv; } - rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector & amounts, const int mixin) { + rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector & amounts, const keyV &amount_keys, const int mixin) { unsigned int index; ctkeyM mixRing; ctkeyV outSk; tie(mixRing, index) = populateFromBlockchain(inPk, mixin); - return genRct(message, inSk, destinations, amounts, mixRing, index, outSk); + return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, index, outSk); } //RCT simple //for post-rct only - rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector &inamounts, const vector &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const std::vector & index, ctkeyV &outSk) { + rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector &inamounts, const vector &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector & index, ctkeyV &outSk) { CHECK_AND_ASSERT_THROW_MES(inamounts.size() > 0, "Empty inamounts"); 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"); @@ -630,7 +630,7 @@ namespace rct { //mask amount and mask rv.ecdhInfo[i].mask = copy(outSk[i].mask); rv.ecdhInfo[i].amount = d2h(outamounts[i]); - ecdhEncode(rv.ecdhInfo[i], destinations[i]); + ecdhEncodeFromSharedSecret(rv.ecdhInfo[i], amount_keys[i]); } //set txn fee @@ -656,7 +656,7 @@ namespace rct { return rv; } - rctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector &inamounts, const vector &outamounts, xmr_amount txnFee, unsigned int mixin) { + rctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector &inamounts, const vector &outamounts, const keyV &amount_keys, xmr_amount txnFee, unsigned int mixin) { std::vector index; index.resize(inPk.size()); ctkeyM mixRing; @@ -666,7 +666,7 @@ namespace rct { mixRing[i].resize(mixin+1); index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin); } - return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, index, outSk); + return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, amount_keys, index, outSk); } //RingCT protocol @@ -782,7 +782,7 @@ namespace rct { //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 // 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) { + static xmr_amount decodeRctMain(const rctSig & rv, const key & sk, unsigned int i, key & mask, void (*decode)(ecdhTuple&, const key&)) { 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.outPk.size() == rv.rangeSigs.size(), "Mismatched sizes of rv.outPk and rv.rangeSigs"); @@ -790,7 +790,7 @@ namespace rct { //mask amount and mask ecdhTuple ecdh_info = rv.ecdhInfo[i]; - ecdhDecode(ecdh_info, sk); + (*decode)(ecdh_info, sk); mask = ecdh_info.mask; key amount = ecdh_info.amount; key C = rv.outPk[i].mask; @@ -806,12 +806,20 @@ namespace rct { return h2d(amount); } + xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask) { + return decodeRctMain(rv, sk, i, mask, &ecdhDecode); + } + + xmr_amount decodeRctFromSharedSecret(const rctSig & rv, const key & sk, unsigned int i, key & mask) { + return decodeRctMain(rv, sk, i, mask, &ecdhDecodeFromSharedSecret); + } + xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i) { key mask; return decodeRct(rv, sk, i, mask); } - xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask) { + static xmr_amount decodeRctSimpleMain(const rctSig & rv, const key & sk, unsigned int i, key &mask, void (*decode)(ecdhTuple &ecdh, const key&)) { 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.outPk.size() == rv.rangeSigs.size(), "Mismatched sizes of rv.outPk and rv.rangeSigs"); @@ -819,7 +827,7 @@ namespace rct { //mask amount and mask ecdhTuple ecdh_info = rv.ecdhInfo[i]; - ecdhDecode(ecdh_info, sk); + (*decode)(ecdh_info, sk); mask = ecdh_info.mask; key amount = ecdh_info.amount; key C = rv.outPk[i].mask; @@ -835,6 +843,14 @@ namespace rct { return h2d(amount); } + xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask) { + return decodeRctSimpleMain(rv, sk, i, mask, &ecdhDecode); + } + + xmr_amount decodeRctSimpleFromSharedSecret(const rctSig & rv, const key & sk, unsigned int i, key &mask) { + return decodeRctSimpleMain(rv, sk, i, mask, &ecdhDecodeFromSharedSecret); + } + xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i) { key mask; return decodeRctSimple(rv, sk, i, mask); -- cgit v1.2.3 From c5be4b0beaaa7a703d4e2b84aa9f3c727bf992df Mon Sep 17 00:00:00 2001 From: Shen Noether Date: Mon, 8 Aug 2016 12:54:00 +0100 Subject: 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/ringct/rctSigs.cpp | 62 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 21 deletions(-) (limited to 'src/ringct/rctSigs.cpp') 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"); } } -- cgit v1.2.3 From 3ab2ab3e7691dadf91ef39ed477e12f0144b8278 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Mon, 8 Aug 2016 13:49:42 +0100 Subject: rct: change the simple flag to a type for future expansion --- src/ringct/rctSigs.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index c252645f8..d031f6c79 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -563,7 +563,7 @@ namespace rct { } rctSig rv; - rv.simple = false; + rv.type = RCTTypeFull; rv.outPk.resize(destinations.size()); rv.rangeSigs.resize(destinations.size()); rv.ecdhInfo.resize(destinations.size()); @@ -625,7 +625,7 @@ namespace rct { } rctSig rv; - rv.simple = true; + rv.type = RCTTypeSimple; rv.message = message; rv.outPk.resize(destinations.size()); rv.rangeSigs.resize(destinations.size()); @@ -700,7 +700,7 @@ namespace rct { // 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 bool verRct(const rctSig & rv, const ctkeyM &mixRing, const keyV &II, const ctkeyV &outPk, const key &message) { - CHECK_AND_ASSERT_MES(!rv.simple, false, "verRct called on simple rctSig"); + CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "verRct called on non-full rctSig"); CHECK_AND_ASSERT_MES(outPk.size() == rv.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.rangeSigs"); CHECK_AND_ASSERT_MES(outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo"); @@ -739,7 +739,7 @@ namespace rct { size_t i = 0; bool rvb = true; - CHECK_AND_ASSERT_MES(rv.simple, false, "verRctSimple called on non simple rctSig"); + CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, false, "verRctSimple called on non simple rctSig"); CHECK_AND_ASSERT_MES(outPk.size() == rv.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.rangeSigs"); CHECK_AND_ASSERT_MES(outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo"); CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.MGs.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.MGs"); @@ -803,7 +803,7 @@ namespace rct { // 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 static xmr_amount decodeRctMain(const rctSig & rv, const key & sk, unsigned int i, key & mask, void (*decode)(ecdhTuple&, const key&)) { - CHECK_AND_ASSERT_MES(!rv.simple, false, "decodeRct called on simple rctSig"); + CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "decodeRct called on non-full rctSig"); 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(i < rv.ecdhInfo.size(), "Bad index"); @@ -840,7 +840,7 @@ namespace rct { } static xmr_amount decodeRctSimpleMain(const rctSig & rv, const key & sk, unsigned int i, key &mask, void (*decode)(ecdhTuple &ecdh, const key&)) { - CHECK_AND_ASSERT_MES(rv.simple, false, "decodeRct called on non simple rctSig"); + CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, 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.outPk.size() == rv.rangeSigs.size(), "Mismatched sizes of rv.outPk and rv.rangeSigs"); CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index"); -- cgit v1.2.3 From d93746b6d37dd5b99d16331ec8e24e8a1f7e4652 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Tue, 9 Aug 2016 11:38:54 +0100 Subject: rct: rework the verification preparation process The whole rct data apart from the MLSAGs is now included in the signed message, to avoid malleability issues. Instead of passing the data that's not serialized as extra parameters to the verification API, the transaction is modified to fill all that information. This means the transaction can not be const anymore, but it cleaner in other ways. --- src/ringct/rctSigs.cpp | 134 +++++++++++++++++++++++++++---------------------- 1 file changed, 75 insertions(+), 59 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index d031f6c79..ca38f13dd 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -237,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, size_t dsRows) { + bool MLSAG_Ver(key message, const keyM & pk, const mgSig & rv, size_t dsRows) { size_t cols = pk.size(); CHECK_AND_ASSERT_MES(cols >= 2, false, "Error! What is c if cols = 1!"); @@ -246,7 +246,7 @@ 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() == dsRows, false, "Bad II size"); + CHECK_AND_ASSERT_MES(rv.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"); @@ -258,7 +258,7 @@ namespace rct { key c_old = copy(rv.cc); vector Ip(dsRows); for (i = 0 ; i < dsRows ; i++) { - precomp(Ip[i].k, II[i]); + precomp(Ip[i].k, rv.II[i]); } size_t ndsRows = 3 * dsRows; //non Double Spendable Rows (see identity chains paper keyV toHash(1 + 3 * dsRows + 2 * (rows - dsRows)); @@ -341,6 +341,43 @@ namespace rct { return (reb && rab); } + key get_pre_mlsag_hash(const rctSig &rv) + { + keyV kv; + kv.push_back(d2h(rv.type)); + kv.push_back(rv.message); + for (auto r: rv.rangeSigs) + { + for (size_t n = 0; n < 64; ++n) + kv.push_back(r.asig.L1[n]); + for (size_t n = 0; n < 64; ++n) + kv.push_back(r.asig.s2[n]); + kv.push_back(r.asig.s); + for (size_t n = 0; n < 64; ++n) + kv.push_back(r.Ci[n]); + } + // no MG/MGs, that's what will sign all this + // no mixRing, it's part of the vin already + for (auto o: rv.pseudoOuts) + { + kv.push_back(o); + } + for (auto i: rv.ecdhInfo) + { + kv.push_back(i.mask); + kv.push_back(i.amount); + // no senderPk, unused here + } + for (auto o: rv.outPk) + { + kv.push_back(o.dest); + kv.push_back(o.mask); + } + kv.push_back(d2h(rv.txnFee)); + + return cn_fast_hash(kv); + } + //Ring-ct MG sigs //Prove: // c.f. http://eprint.iacr.org/2015/1098 section 4. definition 10. @@ -393,10 +430,7 @@ namespace rct { 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.. } - 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, rows); + return MLSAG_Gen(message, M, sk, index, rows); } @@ -435,7 +469,7 @@ namespace rct { // this shows that sum inputs = sum outputs //Ver: // verifies the above sig is created corretly - bool verRctMG(mgSig mg, const keyV &II, const ctkeyM & pubs, const ctkeyV & outPk, key txnFeeKey, const key &message) { + bool verRctMG(mgSig mg, const ctkeyM & pubs, const ctkeyV & outPk, key txnFeeKey, const key &message) { //setup vars size_t cols = pubs.size(); CHECK_AND_ASSERT_MES(cols >= 1, false, "Empty pubs"); @@ -466,19 +500,14 @@ namespace rct { //subtract txn fee output in last row subKeys(M[i][rows], M[i][rows], txnFeeKey); } - ctkeyV signed_data = outPk; - signed_data.push_back(ctkey({message, identity()})); - key msg = cn_fast_hash(signed_data); - DP("message:"); - DP(msg); - return MLSAG_Ver(msg, M, mg, II, rows); + return MLSAG_Ver(message, M, mg, rows); } //Ring-ct Simple MG sigs //Ver: //This does a simplified version, assuming only post Rct //inputs - 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 ctkeyV & pubs, const key & C) { //setup vars size_t rows = 1; size_t cols = pubs.size(); @@ -492,7 +521,7 @@ namespace rct { subKeys(M[i][1], pubs[i].mask, C); } //DP(C); - return MLSAG_Ver(message, M, mg, II, rows); + return MLSAG_Ver(message, M, mg, rows); } //These functions get keys from blockchain @@ -599,8 +628,7 @@ namespace rct { key txnFeeKey = scalarmultH(d2h(rv.txnFee)); rv.mixRing = mixRing; - rv.message = message; - rv.MG = proveRctMG(message, rv.mixRing, inSk, outSk, rv.outPk, index, txnFeeKey); + rv.MG = proveRctMG(get_pre_mlsag_hash(rv), rv.mixRing, inSk, outSk, rv.outPk, index, txnFeeKey); return rv; } @@ -626,7 +654,6 @@ namespace rct { rctSig rv; rv.type = RCTTypeSimple; - rv.message = message; rv.outPk.resize(destinations.size()); rv.rangeSigs.resize(destinations.size()); rv.ecdhInfo.resize(destinations.size()); @@ -661,18 +688,21 @@ namespace rct { rv.pseudoOuts.resize(inamounts.size()); rv.MGs.resize(inamounts.size()); key sumpouts = zero(); //sum pseudoOut masks - key a; + keyV a(inamounts.size()); for (i = 0 ; i < inamounts.size() - 1; i++) { - skGen(a); - sc_add(sumpouts.bytes, a.bytes, sumpouts.bytes); - genC(rv.pseudoOuts[i], a, inamounts[i]); - rv.MGs[i] = proveRctMGSimple(message, rv.mixRing[i], inSk[i], a, rv.pseudoOuts[i], index[i]); + skGen(a[i]); + sc_add(sumpouts.bytes, a[i].bytes, sumpouts.bytes); + genC(rv.pseudoOuts[i], a[i], inamounts[i]); } rv.mixRing = mixRing; - sc_sub(a.bytes, sumout.bytes, sumpouts.bytes); - genC(rv.pseudoOuts[i], a, inamounts[i]); + sc_sub(a[i].bytes, sumout.bytes, sumpouts.bytes); + genC(rv.pseudoOuts[i], a[i], inamounts[i]); DP(rv.pseudoOuts[i]); - rv.MGs[i] = proveRctMGSimple(message, rv.mixRing[i], inSk[i], a, rv.pseudoOuts[i], index[i]); + + key full_message = get_pre_mlsag_hash(rv); + for (i = 0 ; i < inamounts.size(); i++) { + rv.MGs[i] = proveRctMGSimple(full_message, rv.mixRing[i], inSk[i], a[i], rv.pseudoOuts[i], index[i]); + } return rv; } @@ -699,10 +729,10 @@ namespace rct { //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 // 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 ctkeyV &outPk, const key &message) { + bool verRct(const rctSig & rv) { CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "verRct called on non-full rctSig"); - CHECK_AND_ASSERT_MES(outPk.size() == rv.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.rangeSigs"); - CHECK_AND_ASSERT_MES(outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo"); + CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.rangeSigs"); + CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo"); // some rct ops can throw try @@ -711,14 +741,14 @@ namespace rct { bool rvb = true; bool tmp; DP("range proofs verified?"); - for (i = 0; i < outPk.size(); i++) { - tmp = verRange(outPk[i].mask, rv.rangeSigs[i]); + for (i = 0; i < rv.outPk.size(); i++) { + tmp = verRange(rv.outPk[i].mask, rv.rangeSigs[i]); DP(tmp); rvb = (rvb && tmp); } //compute txn fee key txnFeeKey = scalarmultH(d2h(rv.txnFee)); - bool mgVerd = verRctMG(rv.MG, II, mixRing, outPk, txnFeeKey, message); + bool mgVerd = verRctMG(rv.MG, rv.mixRing, rv.outPk, txnFeeKey, get_pre_mlsag_hash(rv)); DP("mg sig verified?"); DP(mgVerd); @@ -729,45 +759,35 @@ namespace rct { return false; } } - bool verRct(const rctSig & rv) { - return verRct(rv, rv.mixRing, rv.MG.II, rv.outPk, rv.message); - } - + //ver RingCT simple //assumes only post-rct style inputs (at least for max anonymity) - bool verRctSimple(const rctSig & rv, const ctkeyM &mixRing, const std::vector *II, const ctkeyV &outPk, const key &message) { + bool verRctSimple(const rctSig & rv) { size_t i = 0; bool rvb = true; - + CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, false, "verRctSimple called on non simple rctSig"); - CHECK_AND_ASSERT_MES(outPk.size() == rv.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.rangeSigs"); - CHECK_AND_ASSERT_MES(outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo"); + CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.rangeSigs"); + CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of 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() == 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() == 1, false, "Bad II size"); - } - } + CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.pseudoOuts and mixRing"); key sumOutpks = identity(); - for (i = 0; i < outPk.size(); i++) { - if (!verRange(outPk[i].mask, rv.rangeSigs[i])) { + for (i = 0; i < rv.outPk.size(); i++) { + if (!verRange(rv.outPk[i].mask, rv.rangeSigs[i])) { return false; } - addKeys(sumOutpks, sumOutpks, outPk[i].mask); + addKeys(sumOutpks, sumOutpks, rv.outPk[i].mask); } DP(sumOutpks); key txnFeeKey = scalarmultH(d2h(rv.txnFee)); addKeys(sumOutpks, txnFeeKey, sumOutpks); bool tmpb = false; + key message = get_pre_mlsag_hash(rv); key sumPseudoOuts = identity(); - for (i = 0 ; i < mixRing.size() ; i++) { - tmpb = verRctMGSimple(message, rv.MGs[i], II ? (*II)[i] : rv.MGs[i].II, mixRing[i], rv.pseudoOuts[i]); + for (i = 0 ; i < rv.mixRing.size() ; i++) { + tmpb = verRctMGSimple(message, rv.MGs[i], rv.mixRing[i], rv.pseudoOuts[i]); addKeys(sumPseudoOuts, sumPseudoOuts, rv.pseudoOuts[i]); DP(tmpb); if (!tmpb) { @@ -788,10 +808,6 @@ namespace rct { return (rvb && mgVerd); } - bool verRctSimple(const rctSig & rv) { - return verRctSimple(rv, rv.mixRing, NULL, rv.outPk, rv.message); - } - //RingCT protocol //genRct: // creates an rctSig with all data necessary to verify the rangeProofs and that the signer owns one of the -- cgit v1.2.3 From 93f5c625f058ee1f81c02c8bb03744b28bbde90a Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Tue, 9 Aug 2016 21:34:09 +0100 Subject: rct: rework v2 txes into prunable and non prunable data Nothing is pruned, but this allows easier changes later. --- src/ringct/rctSigs.cpp | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index ca38f13dd..d42be0fcc 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -346,7 +346,7 @@ namespace rct { keyV kv; kv.push_back(d2h(rv.type)); kv.push_back(rv.message); - for (auto r: rv.rangeSigs) + for (auto r: rv.p.rangeSigs) { for (size_t n = 0; n < 64; ++n) kv.push_back(r.asig.L1[n]); @@ -593,8 +593,9 @@ namespace rct { rctSig rv; rv.type = RCTTypeFull; + rv.message = message; rv.outPk.resize(destinations.size()); - rv.rangeSigs.resize(destinations.size()); + rv.p.rangeSigs.resize(destinations.size()); rv.ecdhInfo.resize(destinations.size()); size_t i = 0; @@ -604,9 +605,9 @@ namespace rct { //add destination to sig rv.outPk[i].dest = copy(destinations[i]); //compute range proof - rv.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, amounts[i]); + rv.p.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, amounts[i]); #ifdef DBG - CHECK_AND_ASSERT_THROW_MES(verRange(rv.outPk[i].mask, rv.rangeSigs[i]), "verRange failed on newly created proof"); + CHECK_AND_ASSERT_THROW_MES(verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]), "verRange failed on newly created proof"); #endif //mask amount and mask @@ -628,7 +629,7 @@ namespace rct { key txnFeeKey = scalarmultH(d2h(rv.txnFee)); rv.mixRing = mixRing; - rv.MG = proveRctMG(get_pre_mlsag_hash(rv), rv.mixRing, inSk, outSk, rv.outPk, index, txnFeeKey); + rv.p.MGs.push_back(proveRctMG(get_pre_mlsag_hash(rv), rv.mixRing, inSk, outSk, rv.outPk, index, txnFeeKey)); return rv; } @@ -654,8 +655,9 @@ namespace rct { rctSig rv; rv.type = RCTTypeSimple; + rv.message = message; rv.outPk.resize(destinations.size()); - rv.rangeSigs.resize(destinations.size()); + rv.p.rangeSigs.resize(destinations.size()); rv.ecdhInfo.resize(destinations.size()); size_t i; @@ -667,9 +669,9 @@ namespace rct { //add destination to sig rv.outPk[i].dest = copy(destinations[i]); //compute range proof - rv.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, outamounts[i]); + rv.p.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, outamounts[i]); #ifdef DBG - verRange(rv.outPk[i].mask, rv.rangeSigs[i]); + verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]); #endif sc_add(sumout.bytes, outSk[i].mask.bytes, sumout.bytes); @@ -686,7 +688,7 @@ namespace rct { // key txnFeeKey = scalarmultH(d2h(rv.txnFee)); rv.mixRing = mixRing; rv.pseudoOuts.resize(inamounts.size()); - rv.MGs.resize(inamounts.size()); + rv.p.MGs.resize(inamounts.size()); key sumpouts = zero(); //sum pseudoOut masks keyV a(inamounts.size()); for (i = 0 ; i < inamounts.size() - 1; i++) { @@ -701,7 +703,7 @@ namespace rct { key full_message = get_pre_mlsag_hash(rv); for (i = 0 ; i < inamounts.size(); i++) { - rv.MGs[i] = proveRctMGSimple(full_message, rv.mixRing[i], inSk[i], a[i], rv.pseudoOuts[i], index[i]); + rv.p.MGs[i] = proveRctMGSimple(full_message, rv.mixRing[i], inSk[i], a[i], rv.pseudoOuts[i], index[i]); } return rv; } @@ -731,8 +733,9 @@ namespace rct { // must know the destination private key to find the correct amount, else will return a random number bool verRct(const rctSig & rv) { CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "verRct called on non-full rctSig"); - CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.rangeSigs"); + CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs"); CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo"); + CHECK_AND_ASSERT_MES(rv.p.MGs.size() == 1, false, "full rctSig has not one MG"); // some rct ops can throw try @@ -742,13 +745,13 @@ namespace rct { bool tmp; DP("range proofs verified?"); for (i = 0; i < rv.outPk.size(); i++) { - tmp = verRange(rv.outPk[i].mask, rv.rangeSigs[i]); + tmp = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]); DP(tmp); rvb = (rvb && tmp); } //compute txn fee key txnFeeKey = scalarmultH(d2h(rv.txnFee)); - bool mgVerd = verRctMG(rv.MG, rv.mixRing, rv.outPk, txnFeeKey, get_pre_mlsag_hash(rv)); + bool mgVerd = verRctMG(rv.p.MGs[0], rv.mixRing, rv.outPk, txnFeeKey, get_pre_mlsag_hash(rv)); DP("mg sig verified?"); DP(mgVerd); @@ -767,14 +770,14 @@ namespace rct { bool rvb = true; CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, false, "verRctSimple called on non simple rctSig"); - CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.rangeSigs"); + CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs"); CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of 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.p.MGs.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.p.MGs"); CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.pseudoOuts and mixRing"); key sumOutpks = identity(); for (i = 0; i < rv.outPk.size(); i++) { - if (!verRange(rv.outPk[i].mask, rv.rangeSigs[i])) { + if (!verRange(rv.outPk[i].mask, rv.p.rangeSigs[i])) { return false; } addKeys(sumOutpks, sumOutpks, rv.outPk[i].mask); @@ -787,7 +790,7 @@ namespace rct { key message = get_pre_mlsag_hash(rv); key sumPseudoOuts = identity(); for (i = 0 ; i < rv.mixRing.size() ; i++) { - tmpb = verRctMGSimple(message, rv.MGs[i], rv.mixRing[i], rv.pseudoOuts[i]); + tmpb = verRctMGSimple(message, rv.p.MGs[i], rv.mixRing[i], rv.pseudoOuts[i]); addKeys(sumPseudoOuts, sumPseudoOuts, rv.pseudoOuts[i]); DP(tmpb); if (!tmpb) { @@ -820,8 +823,8 @@ namespace rct { // must know the destination private key to find the correct amount, else will return a random number static xmr_amount decodeRctMain(const rctSig & rv, const key & sk, unsigned int i, key & mask, void (*decode)(ecdhTuple&, const key&)) { CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "decodeRct called on non-full rctSig"); - 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.p.rangeSigs.size() > 0, "Empty rv.p.rangeSigs"); + CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.p.rangeSigs.size(), "Mismatched sizes of rv.outPk and rv.p.rangeSigs"); CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index"); //mask amount and mask @@ -857,8 +860,8 @@ namespace rct { static xmr_amount decodeRctSimpleMain(const rctSig & rv, const key & sk, unsigned int i, key &mask, void (*decode)(ecdhTuple &ecdh, const key&)) { CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, 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.outPk.size() == rv.rangeSigs.size(), "Mismatched sizes of rv.outPk and rv.rangeSigs"); + CHECK_AND_ASSERT_THROW_MES(rv.p.rangeSigs.size() > 0, "Empty rv.p.rangeSigs"); + CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.p.rangeSigs.size(), "Mismatched sizes of rv.outPk and rv.p.rangeSigs"); CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index"); //mask amount and mask -- cgit v1.2.3 From d4b62a1e295a7fb19de6081733b1d8e0610cbf08 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Wed, 10 Aug 2016 12:48:20 +0100 Subject: rct amount key modified as per luigi1111's recommendations This allows the key to be not the same for two outputs sent to the same address (eg, if you pay yourself, and also get change back). Also remove the key amounts lists and return parameters since we don't actually generate random ones, so we don't need to save them as we can recalculate them when needed if we have the correct keys. --- src/ringct/rctSigs.cpp | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index d42be0fcc..73c124067 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -613,7 +613,7 @@ namespace rct { //mask amount and mask rv.ecdhInfo[i].mask = copy(outSk[i].mask); rv.ecdhInfo[i].amount = d2h(amounts[i]); - ecdhEncodeFromSharedSecret(rv.ecdhInfo[i], amount_keys[i]); + ecdhEncode(rv.ecdhInfo[i], amount_keys[i]); } @@ -679,7 +679,7 @@ namespace rct { //mask amount and mask rv.ecdhInfo[i].mask = copy(outSk[i].mask); rv.ecdhInfo[i].amount = d2h(outamounts[i]); - ecdhEncodeFromSharedSecret(rv.ecdhInfo[i], amount_keys[i]); + ecdhEncode(rv.ecdhInfo[i], amount_keys[i]); } //set txn fee @@ -821,7 +821,7 @@ namespace rct { //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 // must know the destination private key to find the correct amount, else will return a random number - static xmr_amount decodeRctMain(const rctSig & rv, const key & sk, unsigned int i, key & mask, void (*decode)(ecdhTuple&, const key&)) { + xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask) { CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "decodeRct called on non-full rctSig"); CHECK_AND_ASSERT_THROW_MES(rv.p.rangeSigs.size() > 0, "Empty rv.p.rangeSigs"); CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.p.rangeSigs.size(), "Mismatched sizes of rv.outPk and rv.p.rangeSigs"); @@ -829,7 +829,7 @@ namespace rct { //mask amount and mask ecdhTuple ecdh_info = rv.ecdhInfo[i]; - (*decode)(ecdh_info, sk); + ecdhDecode(ecdh_info, sk); mask = ecdh_info.mask; key amount = ecdh_info.amount; key C = rv.outPk[i].mask; @@ -845,20 +845,12 @@ namespace rct { return h2d(amount); } - xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask) { - return decodeRctMain(rv, sk, i, mask, &ecdhDecode); - } - - xmr_amount decodeRctFromSharedSecret(const rctSig & rv, const key & sk, unsigned int i, key & mask) { - return decodeRctMain(rv, sk, i, mask, &ecdhDecodeFromSharedSecret); - } - xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i) { key mask; return decodeRct(rv, sk, i, mask); } - static xmr_amount decodeRctSimpleMain(const rctSig & rv, const key & sk, unsigned int i, key &mask, void (*decode)(ecdhTuple &ecdh, const key&)) { + xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask) { CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, false, "decodeRct called on non simple rctSig"); CHECK_AND_ASSERT_THROW_MES(rv.p.rangeSigs.size() > 0, "Empty rv.p.rangeSigs"); CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.p.rangeSigs.size(), "Mismatched sizes of rv.outPk and rv.p.rangeSigs"); @@ -866,7 +858,7 @@ namespace rct { //mask amount and mask ecdhTuple ecdh_info = rv.ecdhInfo[i]; - (*decode)(ecdh_info, sk); + ecdhDecode(ecdh_info, sk); mask = ecdh_info.mask; key amount = ecdh_info.amount; key C = rv.outPk[i].mask; @@ -882,14 +874,6 @@ namespace rct { return h2d(amount); } - xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask) { - return decodeRctSimpleMain(rv, sk, i, mask, &ecdhDecode); - } - - xmr_amount decodeRctSimpleFromSharedSecret(const rctSig & rv, const key & sk, unsigned int i, key &mask) { - return decodeRctSimpleMain(rv, sk, i, mask, &ecdhDecodeFromSharedSecret); - } - xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i) { key mask; return decodeRctSimple(rv, sk, i, mask); -- cgit v1.2.3 From 6f526cdff815ebc86db61cd7dac9838af1067cb1 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Fri, 12 Aug 2016 18:30:16 +0100 Subject: rct: log why verification fails and remove some unnecessary variables in the checking code --- src/ringct/rctSigs.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 73c124067..62ac2ac06 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -741,21 +741,27 @@ namespace rct { try { size_t i = 0; - bool rvb = true; bool tmp; DP("range proofs verified?"); for (i = 0; i < rv.outPk.size(); i++) { tmp = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]); DP(tmp); - rvb = (rvb && tmp); + if (!tmp) { + LOG_ERROR("Range proof verification failed for input " << i); + return false; + } } //compute txn fee key txnFeeKey = scalarmultH(d2h(rv.txnFee)); bool mgVerd = verRctMG(rv.p.MGs[0], rv.mixRing, rv.outPk, txnFeeKey, get_pre_mlsag_hash(rv)); DP("mg sig verified?"); DP(mgVerd); + if (!mgVerd) { + LOG_ERROR("MG signature verification failed"); + return false; + } - return (rvb && mgVerd); + return true; } catch(...) { @@ -767,7 +773,6 @@ namespace rct { //assumes only post-rct style inputs (at least for max anonymity) bool verRctSimple(const rctSig & rv) { size_t i = 0; - bool rvb = true; CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, false, "verRctSimple called on non simple rctSig"); CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs"); @@ -778,6 +783,7 @@ namespace rct { key sumOutpks = identity(); for (i = 0; i < rv.outPk.size(); i++) { if (!verRange(rv.outPk[i].mask, rv.p.rangeSigs[i])) { + LOG_ERROR("Range proof verified failed for input " << i); return false; } addKeys(sumOutpks, sumOutpks, rv.outPk[i].mask); @@ -794,21 +800,19 @@ namespace rct { addKeys(sumPseudoOuts, sumPseudoOuts, rv.pseudoOuts[i]); DP(tmpb); if (!tmpb) { + LOG_ERROR("verRctMGSimple failed for input " << i); return false; } } DP(sumPseudoOuts); - bool mgVerd = true; //check pseudoOuts vs Outs.. if (!equalKeys(sumPseudoOuts, sumOutpks)) { + LOG_ERROR("Sum check failed"); return false; } - - DP("mg sig verified?"); - DP(mgVerd); - return (rvb && mgVerd); + return true; } //RingCT protocol -- cgit v1.2.3 From 074e60260919fb0da19db125f3c9a16bcff2773f Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Fri, 12 Aug 2016 23:11:51 +0100 Subject: ringct: use Cryptonote serialization to hash non prunable data --- src/ringct/rctSigs.cpp | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 62ac2ac06..348051419 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -30,6 +30,8 @@ #include "misc_log_ex.h" #include "rctSigs.h" +#include "cryptonote_core/cryptonote_format_utils.h" + using namespace crypto; using namespace std; @@ -343,9 +345,12 @@ namespace rct { key get_pre_mlsag_hash(const rctSig &rv) { + keyV hashes; + hashes.push_back(rv.message); + crypto::hash h; + cryptonote::get_blob_hash(cryptonote::t_serializable_object_to_blob((const rctSigBase&)rv), h); + hashes.push_back(hash2rct(h)); keyV kv; - kv.push_back(d2h(rv.type)); - kv.push_back(rv.message); for (auto r: rv.p.rangeSigs) { for (size_t n = 0; n < 64; ++n) @@ -356,26 +361,9 @@ namespace rct { for (size_t n = 0; n < 64; ++n) kv.push_back(r.Ci[n]); } - // no MG/MGs, that's what will sign all this - // no mixRing, it's part of the vin already - for (auto o: rv.pseudoOuts) - { - kv.push_back(o); - } - for (auto i: rv.ecdhInfo) - { - kv.push_back(i.mask); - kv.push_back(i.amount); - // no senderPk, unused here - } - for (auto o: rv.outPk) - { - kv.push_back(o.dest); - kv.push_back(o.mask); - } - kv.push_back(d2h(rv.txnFee)); + hashes.push_back(cn_fast_hash(kv)); - return cn_fast_hash(kv); + return cn_fast_hash(hashes); } //Ring-ct MG sigs -- cgit v1.2.3 From 94fd881f74beaed0ffca5fdca1b3504462715e71 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 27 Aug 2016 10:10:19 +0100 Subject: rct: early out on failure on verRange --- src/ringct/rctSigs.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 348051419..2fedfa761 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -338,9 +338,11 @@ namespace rct { subKeys(CiH[i], as.Ci[i], H2[i]); addKeys(Ctmp, Ctmp, as.Ci[i]); } - bool reb = equalKeys(C, Ctmp); - bool rab = VerASNL(as.Ci, CiH, as.asig); - return (reb && rab); + if (!equalKeys(C, Ctmp)) + return false; + if (!VerASNL(as.Ci, CiH, as.asig)) + return false; + return true; } key get_pre_mlsag_hash(const rctSig &rv) -- cgit v1.2.3 From b38452bd55134e03948a82a6590b58f55e152f97 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 27 Aug 2016 22:20:45 +0100 Subject: ringct: pass structure by const ref, not value --- src/ringct/rctSigs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 2fedfa761..f4dbd65c5 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -459,7 +459,7 @@ namespace rct { // this shows that sum inputs = sum outputs //Ver: // verifies the above sig is created corretly - bool verRctMG(mgSig mg, const ctkeyM & pubs, const ctkeyV & outPk, key txnFeeKey, const key &message) { + bool verRctMG(const mgSig &mg, const ctkeyM & pubs, const ctkeyV & outPk, key txnFeeKey, const key &message) { //setup vars size_t cols = pubs.size(); CHECK_AND_ASSERT_MES(cols >= 1, false, "Empty pubs"); -- cgit v1.2.3