aboutsummaryrefslogtreecommitdiff
path: root/src/ringct/rctSigs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ringct/rctSigs.cpp')
-rw-r--r--src/ringct/rctSigs.cpp106
1 files changed, 84 insertions, 22 deletions
diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp
index 38b213e8b..24ab08778 100644
--- a/src/ringct/rctSigs.cpp
+++ b/src/ringct/rctSigs.cpp
@@ -122,7 +122,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(const key &message, const keyM & pk, const keyV & xx, const unsigned int index, size_t dsRows) {
+ mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const multisig_kLRki *kLRki, key *mscout, 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!");
@@ -134,6 +134,8 @@ namespace rct {
}
CHECK_AND_ASSERT_THROW_MES(xx.size() == rows, "Bad xx size");
CHECK_AND_ASSERT_THROW_MES(dsRows <= rows, "Bad dsRows size");
+ CHECK_AND_ASSERT_THROW_MES((kLRki && mscout) || (!kLRki && !mscout), "Only one of kLRki/mscout is present");
+ CHECK_AND_ASSERT_THROW_MES(!kLRki || dsRows == 1, "Multisig requires exactly 1 dsRows");
size_t i = 0, j = 0, ii = 0;
key c, c_old, L, R, Hi;
@@ -148,13 +150,22 @@ namespace rct {
toHash[0] = message;
DP("here1");
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]);
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]);
+ if (kLRki) {
+ // multisig
+ alpha[i] = kLRki->k;
+ toHash[3 * i + 2] = kLRki->L;
+ toHash[3 * i + 3] = kLRki->R;
+ rv.II[i] = kLRki->ki;
+ }
+ else {
+ Hi = hashToPoint(pk[index][i]);
+ skpkGen(alpha[i], aG[i]); //need to save alphas for later..
+ aHP[i] = scalarmultKey(Hi, alpha[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]);
}
size_t ndsRows = 3 * dsRows; //non Double Spendable Rows (see identity chains paper)
@@ -198,7 +209,9 @@ namespace rct {
}
for (j = 0; j < rows; j++) {
sc_mulsub(rv.ss[index][j].bytes, c.bytes, xx[j].bytes, alpha[j].bytes);
- }
+ }
+ if (mscout)
+ *mscout = c;
return rv;
}
@@ -393,7 +406,7 @@ namespace rct {
// this shows that sum inputs = sum outputs
//Ver:
// verifies the above sig is created corretly
- mgSig proveRctMG(const key &message, const ctkeyM & pubs, const ctkeyV & inSk, const ctkeyV &outSk, const ctkeyV & outPk, unsigned int index, key txnFeeKey) {
+ mgSig proveRctMG(const key &message, const ctkeyM & pubs, const ctkeyV & inSk, const ctkeyV &outSk, const ctkeyV & outPk, const multisig_kLRki *kLRki, key *mscout, unsigned int index, key txnFeeKey) {
mgSig mg;
//setup vars
size_t cols = pubs.size();
@@ -405,6 +418,7 @@ namespace rct {
}
CHECK_AND_ASSERT_THROW_MES(inSk.size() == rows, "Bad inSk size");
CHECK_AND_ASSERT_THROW_MES(outSk.size() == outPk.size(), "Bad outSk/outPk size");
+ CHECK_AND_ASSERT_THROW_MES((kLRki && mscout) || (!kLRki && !mscout), "Only one of kLRki/mscout is present");
keyV sk(rows + 1);
keyV tmp(rows + 1);
@@ -437,7 +451,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..
}
- return MLSAG_Gen(message, M, sk, index, rows);
+ return MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows);
}
@@ -448,12 +462,13 @@ namespace rct {
// 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 proveRctMGSimple(const key &message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, const multisig_kLRki *kLRki, key *mscout, 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");
+ CHECK_AND_ASSERT_THROW_MES((kLRki && mscout) || (!kLRki && !mscout), "Only one of kLRki/mscout is present");
keyV tmp(rows + 1);
keyV sk(rows + 1);
size_t i;
@@ -464,7 +479,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, rows);
+ return MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows);
}
@@ -598,13 +613,14 @@ 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<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, unsigned int index, ctkeyV &outSk, bool bulletproof) {
+ rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, bool bulletproof) {
CHECK_AND_ASSERT_THROW_MES(amounts.size() == destinations.size() || amounts.size() == destinations.size() + 1, "Different number of amounts/destinations");
CHECK_AND_ASSERT_THROW_MES(amount_keys.size() == destinations.size(), "Different number of amount_keys/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");
}
+ CHECK_AND_ASSERT_THROW_MES((kLRki && msout) || (!kLRki && !msout), "Only one of kLRki/msout is present");
rctSig rv;
rv.type = bulletproof ? RCTTypeFullBulletproof : RCTTypeFull;
@@ -653,21 +669,23 @@ namespace rct {
key txnFeeKey = scalarmultH(d2h(rv.txnFee));
rv.mixRing = mixRing;
- rv.p.MGs.push_back(proveRctMG(get_pre_mlsag_hash(rv), rv.mixRing, inSk, outSk, rv.outPk, index, txnFeeKey));
+ if (msout)
+ msout->c.resize(1);
+ rv.p.MGs.push_back(proveRctMG(get_pre_mlsag_hash(rv), rv.mixRing, inSk, outSk, rv.outPk, kLRki, msout ? &msout->c[0] : NULL, index, txnFeeKey));
return rv;
}
- rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & amounts, const keyV &amount_keys, const int mixin) {
+ rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & amounts, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, const int mixin) {
unsigned int index;
ctkeyM mixRing;
ctkeyV outSk;
tie(mixRing, index) = populateFromBlockchain(inPk, mixin);
- return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, index, outSk, false);
+ return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, kLRki, msout, index, outSk, false);
}
//RCT simple
//for post-rct only
- rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<unsigned int> & index, ctkeyV &outSk, bool bulletproof) {
+ rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, const std::vector<unsigned int> & index, ctkeyV &outSk, bool bulletproof) {
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");
@@ -677,6 +695,10 @@ namespace rct {
for (size_t n = 0; n < mixRing.size(); ++n) {
CHECK_AND_ASSERT_THROW_MES(index[n] < mixRing[n].size(), "Bad index into mixRing");
}
+ CHECK_AND_ASSERT_THROW_MES((kLRki && msout) || (!kLRki && !msout), "Only one of kLRki/msout is present");
+ if (kLRki && msout) {
+ CHECK_AND_ASSERT_THROW_MES(kLRki->size() == inamounts.size(), "Mismatched kLRki/inamounts sizes");
+ }
rctSig rv;
rv.type = bulletproof ? RCTTypeSimpleBulletproof : RCTTypeSimple;
@@ -736,13 +758,15 @@ namespace rct {
DP(rv.pseudoOuts[i]);
key full_message = get_pre_mlsag_hash(rv);
+ if (msout)
+ msout->c.resize(inamounts.size());
for (i = 0 ; i < inamounts.size(); i++) {
- rv.p.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], kLRki ? &(*kLRki)[i]: NULL, msout ? &msout->c[i] : NULL, index[i]);
}
return rv;
}
- rctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, const keyV &amount_keys, xmr_amount txnFee, unsigned int mixin) {
+ rctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, xmr_amount txnFee, unsigned int mixin) {
std::vector<unsigned int> index;
index.resize(inPk.size());
ctkeyM mixRing;
@@ -752,7 +776,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, amount_keys, index, outSk, false);
+ return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, amount_keys, kLRki, msout, index, outSk, false);
}
//RingCT protocol
@@ -822,8 +846,14 @@ namespace rct {
return true;
}
- catch(...)
+ catch (const std::exception &e)
{
+ LOG_PRINT_L1("Error in verRct: " << e.what());
+ return false;
+ }
+ catch (...)
+ {
+ LOG_PRINT_L1("Error in verRct, but not an actual exception");
return false;
}
}
@@ -920,7 +950,16 @@ namespace rct {
return true;
}
// we can get deep throws from ge_frombytes_vartime if input isn't valid
- catch (...) { return false; }
+ catch (const std::exception &e)
+ {
+ LOG_PRINT_L1("Error in verRct: " << e.what());
+ return false;
+ }
+ catch (...)
+ {
+ LOG_PRINT_L1("Error in verRct, but not an actual exception");
+ return false;
+ }
}
//RingCT protocol
@@ -988,4 +1027,27 @@ namespace rct {
key mask;
return decodeRctSimple(rv, sk, i, mask);
}
+
+ bool signMultisig(rctSig &rv, const std::vector<unsigned int> &indices, const keyV &k, const multisig_out &msout, const key &secret_key) {
+ CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull || rv.type == RCTTypeSimple || rv.type == RCTTypeFullBulletproof || rv.type == RCTTypeSimpleBulletproof,
+ false, "unsupported rct type");
+ CHECK_AND_ASSERT_MES(indices.size() == k.size(), false, "Mismatched k/indices sizes");
+ CHECK_AND_ASSERT_MES(k.size() == rv.p.MGs.size(), false, "Mismatched k/MGs size");
+ CHECK_AND_ASSERT_MES(k.size() == msout.c.size(), false, "Mismatched k/msout.c size");
+ if (rv.type == RCTTypeFull || rv.type == RCTTypeFullBulletproof)
+ {
+ CHECK_AND_ASSERT_MES(rv.p.MGs.size() == 1, false, "MGs not a single element");
+ }
+ for (size_t n = 0; n < indices.size(); ++n) {
+ CHECK_AND_ASSERT_MES(indices[n] < rv.p.MGs[n].ss.size(), false, "Index out of range");
+ CHECK_AND_ASSERT_MES(!rv.p.MGs[n].ss[indices[n]].empty(), false, "empty ss line");
+ }
+
+ for (size_t n = 0; n < indices.size(); ++n) {
+ rct::key diff;
+ sc_mulsub(diff.bytes, msout.c[n].bytes, secret_key.bytes, k[n].bytes);
+ sc_add(rv.p.MGs[n].ss[indices[n]][0].bytes, rv.p.MGs[n].ss[indices[n]][0].bytes, diff.bytes);
+ }
+ return true;
+ }
}