aboutsummaryrefslogtreecommitdiff
path: root/src/ringct/rctSigs.cpp
diff options
context:
space:
mode:
authoranon <anon [at] nowhere>2021-12-06 10:25:01 +0000
committerkoe <ukoe@protonmail.com>2022-06-30 12:56:40 -0500
commitc7b2944f8960c208ceddeb3075a673630ae000cd (patch)
tree5ab335821b3dd9398a7a0ec645b4ad79d38e750b /src/ringct/rctSigs.cpp
parentMerge pull request #8340 (diff)
downloadmonero-c7b2944f8960c208ceddeb3075a673630ae000cd.tar.xz
multisig: fix critical vulnerabilities in signing
Diffstat (limited to 'src/ringct/rctSigs.cpp')
-rw-r--r--src/ringct/rctSigs.cpp164
1 files changed, 28 insertions, 136 deletions
diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp
index bd67778ec..21040317c 100644
--- a/src/ringct/rctSigs.cpp
+++ b/src/ringct/rctSigs.cpp
@@ -238,14 +238,12 @@ namespace rct {
// P[l] == p*G
// C[l] == z*G
// C[i] == C_nonzero[i] - C_offset (for hashing purposes) for all i
- clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const keyV & C_nonzero, const key & C_offset, const unsigned int l, const multisig_kLRki *kLRki, key *mscout, key *mspout, hw::device &hwdev) {
+ clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const keyV & C_nonzero, const key & C_offset, const unsigned int l, hw::device &hwdev) {
clsag sig;
size_t n = P.size(); // ring size
CHECK_AND_ASSERT_THROW_MES(n == C.size(), "Signing and commitment key vector sizes must match!");
CHECK_AND_ASSERT_THROW_MES(n == C_nonzero.size(), "Signing and commitment key vector sizes must match!");
CHECK_AND_ASSERT_THROW_MES(l < n, "Signing index out of range!");
- CHECK_AND_ASSERT_THROW_MES((kLRki && mscout) || (!kLRki && !mscout), "Only one of kLRki/mscout is present");
- CHECK_AND_ASSERT_THROW_MES((mscout && mspout) || !kLRki, "Multisig pointers are not all present");
// Key images
ge_p3 H_p3;
@@ -260,16 +258,7 @@ namespace rct {
key aG;
key aH;
- // Multisig
- if (kLRki)
- {
- sig.I = kLRki->ki;
- scalarmultKey(D,H,z);
- }
- else
- {
- hwdev.clsag_prepare(p,z,sig.I,D,H,a,aG,aH);
- }
+ hwdev.clsag_prepare(p,z,sig.I,D,H,a,aG,aH);
geDsmp I_precomp;
geDsmp D_precomp;
@@ -317,18 +306,9 @@ namespace rct {
c_to_hash[2*n+1] = C_offset;
c_to_hash[2*n+2] = message;
- // Multisig data is present
- if (kLRki)
- {
- a = kLRki->k;
- c_to_hash[2*n+3] = kLRki->L;
- c_to_hash[2*n+4] = kLRki->R;
- }
- else
- {
- c_to_hash[2*n+3] = aG;
- c_to_hash[2*n+4] = aH;
- }
+ c_to_hash[2*n+3] = aG;
+ c_to_hash[2*n+4] = aH;
+
hwdev.clsag_hash(c_to_hash,c);
size_t i;
@@ -380,16 +360,11 @@ namespace rct {
hwdev.clsag_sign(c,a,p,z,mu_P,mu_C,sig.s[l]);
memwipe(&a, sizeof(key));
- if (mscout)
- *mscout = c;
- if (mspout)
- *mspout = mu_P;
-
return sig;
}
clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const keyV & C_nonzero, const key & C_offset, const unsigned int l) {
- return CLSAG_Gen(message, P, p, C, z, C_nonzero, C_offset, l, NULL, NULL, NULL, hw::get_device("default"));
+ return CLSAG_Gen(message, P, p, C, z, C_nonzero, C_offset, l, hw::get_device("default"));
}
// MLSAG signatures
@@ -397,7 +372,7 @@ namespace rct {
// This generalization allows for some dimensions not to require linkability;
// this is used in practice for commitment data within signatures
// Note that using more than one linkable dimension is not recommended.
- 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, hw::device &hwdev) {
+ mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const unsigned int index, size_t dsRows, hw::device &hwdev) {
mgSig rv;
size_t cols = pk.size();
CHECK_AND_ASSERT_THROW_MES(cols >= 2, "Error! What is c if cols = 1!");
@@ -409,8 +384,6 @@ 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;
@@ -428,20 +401,11 @@ namespace rct {
DP("here1");
for (i = 0; i < dsRows; i++) {
toHash[3 * i + 1] = pk[index][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 {
- hash_to_p3(Hi_p3, pk[index][i]);
- ge_p3_tobytes(Hi.bytes, &Hi_p3);
- hwdev.mlsag_prepare(Hi, xx[i], alpha[i] , aG[i] , aHP[i] , rv.II[i]);
- toHash[3 * i + 2] = aG[i];
- toHash[3 * i + 3] = aHP[i];
- }
+ hash_to_p3(Hi_p3, pk[index][i]);
+ ge_p3_tobytes(Hi.bytes, &Hi_p3);
+ hwdev.mlsag_prepare(Hi, xx[i], alpha[i] , aG[i] , aHP[i] , rv.II[i]);
+ toHash[3 * i + 2] = aG[i];
+ toHash[3 * i + 3] = aHP[i];
precomp(Ip[i].k, rv.II[i]);
}
size_t ndsRows = 3 * dsRows; //non Double Spendable Rows (see identity chains paper)
@@ -485,8 +449,6 @@ namespace rct {
}
}
hwdev.mlsag_sign(c, xx, alpha, rows, dsRows, rv.ss[index]);
- if (mscout)
- *mscout = c;
return rv;
}
@@ -722,7 +684,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, const multisig_kLRki *kLRki, key *mscout, unsigned int index, const key &txnFeeKey, hw::device &hwdev) {
+ mgSig proveRctMG(const key &message, const ctkeyM & pubs, const ctkeyV & inSk, const ctkeyV &outSk, const ctkeyV & outPk, unsigned int index, const key &txnFeeKey, hw::device &hwdev) {
//setup vars
size_t cols = pubs.size();
CHECK_AND_ASSERT_THROW_MES(cols >= 1, "Empty pubs");
@@ -733,7 +695,6 @@ 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);
@@ -766,7 +727,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..
}
- mgSig result = MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows, hwdev);
+ mgSig result = MLSAG_Gen(message, M, sk, index, rows, hwdev);
memwipe(sk.data(), sk.size() * sizeof(key));
return result;
}
@@ -779,12 +740,11 @@ 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, const multisig_kLRki *kLRki, key *mscout, unsigned int index, hw::device &hwdev) {
+ mgSig proveRctMGSimple(const key &message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, unsigned int index, hw::device &hwdev) {
//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;
@@ -796,17 +756,16 @@ namespace rct {
M[i][0] = pubs[i].dest;
subKeys(M[i][1], pubs[i].mask, Cout);
}
- mgSig result = MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows, hwdev);
+ mgSig result = MLSAG_Gen(message, M, sk, index, rows, hwdev);
memwipe(sk.data(), sk.size() * sizeof(key));
return result;
}
- clsag proveRctCLSAGSimple(const key &message, const ctkeyV &pubs, const ctkey &inSk, const key &a, const key &Cout, const multisig_kLRki *kLRki, key *mscout, key *mspout, unsigned int index, hw::device &hwdev) {
+ clsag proveRctCLSAGSimple(const key &message, const ctkeyV &pubs, const ctkey &inSk, const key &a, const key &Cout, unsigned int index, hw::device &hwdev) {
//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);
keyM M(cols, tmp);
@@ -826,7 +785,7 @@ namespace rct {
sk[0] = copy(inSk.dest);
sc_sub(sk[1].bytes, inSk.mask.bytes, a.bytes);
- clsag result = CLSAG_Gen(message, P, sk[0], C, sk[1], C_nonzero, Cout, index, kLRki, mscout, mspout, hwdev);
+ clsag result = CLSAG_Gen(message, P, sk[0], C, sk[1], C_nonzero, Cout, index, hwdev);
memwipe(sk.data(), sk.size() * sizeof(key));
return result;
}
@@ -1084,14 +1043,13 @@ 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, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, const RCTConfig &rct_config, hw::device &hwdev) {
+ 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, const RCTConfig &rct_config, hw::device &hwdev) {
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");
CHECK_AND_ASSERT_THROW_MES(inSk.size() < 2, "genRct is not suitable for 2+ rings");
rctSig rv;
@@ -1130,23 +1088,21 @@ namespace rct {
key txnFeeKey = scalarmultH(d2h(rv.txnFee));
rv.mixRing = mixRing;
- if (msout)
- msout->c.resize(1);
- rv.p.MGs.push_back(proveRctMG(get_pre_mlsag_hash(rv, hwdev), rv.mixRing, inSk, outSk, rv.outPk, kLRki, msout ? &msout->c[0] : NULL, index, txnFeeKey,hwdev));
+ rv.p.MGs.push_back(proveRctMG(get_pre_mlsag_hash(rv, hwdev), rv.mixRing, inSk, outSk, rv.outPk, index, txnFeeKey,hwdev));
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 multisig_kLRki *kLRki, multisig_out *msout, const int mixin, const RCTConfig &rct_config, hw::device &hwdev) {
+ 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, const RCTConfig &rct_config, hw::device &hwdev) {
unsigned int index;
ctkeyM mixRing;
ctkeyV outSk;
tie(mixRing, index) = populateFromBlockchain(inPk, mixin);
- return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, kLRki, msout, index, outSk, rct_config, hwdev);
+ return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, index, outSk, rct_config, hwdev);
}
//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<multisig_kLRki> *kLRki, multisig_out *msout, const std::vector<unsigned int> & index, ctkeyV &outSk, const RCTConfig &rct_config, hw::device &hwdev) {
+ 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, const RCTConfig &rct_config, hw::device &hwdev) {
const bool bulletproof_or_plus = rct_config.range_proof_type > RangeProofBorromean;
CHECK_AND_ASSERT_THROW_MES(inamounts.size() > 0, "Empty inamounts");
CHECK_AND_ASSERT_THROW_MES(inamounts.size() == inSk.size(), "Different number of inamounts/inSk");
@@ -1157,10 +1113,6 @@ 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;
if (bulletproof_or_plus)
@@ -1322,11 +1274,7 @@ namespace rct {
DP(pseudoOuts[i]);
key full_message = get_pre_mlsag_hash(rv,hwdev);
- if (msout)
- {
- msout->c.resize(inamounts.size());
- msout->mu_p.resize(is_rct_clsag(rv.type) ? inamounts.size() : 0);
- }
+
for (i = 0 ; i < inamounts.size(); i++)
{
if (is_rct_clsag(rv.type))
@@ -1334,17 +1282,17 @@ namespace rct {
if (hwdev.get_mode() == hw::device::TRANSACTION_CREATE_FAKE)
rv.p.CLSAGs[i] = make_dummy_clsag(rv.mixRing[i].size());
else
- rv.p.CLSAGs[i] = proveRctCLSAGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], kLRki ? &(*kLRki)[i]: NULL, msout ? &msout->c[i] : NULL, msout ? &msout->mu_p[i] : NULL, index[i], hwdev);
+ rv.p.CLSAGs[i] = proveRctCLSAGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], index[i], hwdev);
}
else
{
- rv.p.MGs[i] = proveRctMGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], kLRki ? &(*kLRki)[i]: NULL, msout ? &msout->c[i] : NULL, index[i], hwdev);
+ rv.p.MGs[i] = proveRctMGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], index[i], hwdev);
}
}
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, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, xmr_amount txnFee, unsigned int mixin, const RCTConfig &rct_config, hw::device &hwdev) {
+ 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, const RCTConfig &rct_config, hw::device &hwdev) {
std::vector<unsigned int> index;
index.resize(inPk.size());
ctkeyM mixRing;
@@ -1354,7 +1302,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, kLRki, msout, index, outSk, rct_config, hwdev);
+ return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, amount_keys, index, outSk, rct_config, hwdev);
}
//RingCT protocol
@@ -1700,60 +1648,4 @@ namespace rct {
key mask;
return decodeRctSimple(rv, sk, i, mask, hwdev);
}
-
- bool signMultisigMLSAG(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 == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2,
- false, "unsupported rct type");
- CHECK_AND_ASSERT_MES(!is_rct_clsag(rv.type), false, "CLSAG signature type in MLSAG signature function");
- 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");
- CHECK_AND_ASSERT_MES(rv.p.CLSAGs.empty(), false, "CLSAGs not empty for MLSAGs");
- if (rv.type == RCTTypeFull)
- {
- 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");
- }
-
- // MLSAG: each player contributes a share to the secret-index ss: k - cc*secret_key_share
- // cc: msout.c[n], secret_key_share: secret_key
- 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;
- }
-
- bool signMultisigCLSAG(rctSig &rv, const std::vector<unsigned int> &indices, const keyV &k, const multisig_out &msout, const key &secret_key) {
- CHECK_AND_ASSERT_MES(is_rct_clsag(rv.type), 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.CLSAGs.size(), false, "Mismatched k/CLSAGs size");
- CHECK_AND_ASSERT_MES(k.size() == msout.c.size(), false, "Mismatched k/msout.c size");
- CHECK_AND_ASSERT_MES(rv.p.MGs.empty(), false, "MGs not empty for CLSAGs");
- CHECK_AND_ASSERT_MES(msout.c.size() == msout.mu_p.size(), false, "Bad mu_p size");
- for (size_t n = 0; n < indices.size(); ++n) {
- CHECK_AND_ASSERT_MES(indices[n] < rv.p.CLSAGs[n].s.size(), false, "Index out of range");
- }
-
- // CLSAG: each player contributes a share to the secret-index ss: k - cc*mu_p*secret_key_share
- // cc: msout.c[n], mu_p, msout.mu_p[n], secret_key_share: secret_key
- for (size_t n = 0; n < indices.size(); ++n) {
- rct::key diff, sk;
- sc_mul(sk.bytes, msout.mu_p[n].bytes, secret_key.bytes);
- sc_mulsub(diff.bytes, msout.c[n].bytes, sk.bytes, k[n].bytes);
- sc_add(rv.p.CLSAGs[n].s[indices[n]].bytes, rv.p.CLSAGs[n].s[indices[n]].bytes, diff.bytes);
- }
- return true;
- }
-
- bool signMultisig(rctSig &rv, const std::vector<unsigned int> &indices, const keyV &k, const multisig_out &msout, const key &secret_key) {
- if (is_rct_clsag(rv.type))
- return signMultisigCLSAG(rv, indices, k, msout, secret_key);
- else
- return signMultisigMLSAG(rv, indices, k, msout, secret_key);
- }
}