Electroneum
rctSigs.cpp
Go to the documentation of this file.
1 // Copyright (c) 2016, Electroneum Research Labs
2 //
3 // Author: Shen Noether <shen.noether@gmx.com>
4 //
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without modification, are
8 // permitted provided that the following conditions are met:
9 //
10 // 1. Redistributions of source code must retain the above copyright notice, this list of
11 // conditions and the following disclaimer.
12 //
13 // 2. Redistributions in binary form must reproduce the above copyright notice, this list
14 // of conditions and the following disclaimer in the documentation and/or other
15 // materials provided with the distribution.
16 //
17 // 3. Neither the name of the copyright holder nor the names of its contributors may be
18 // used to endorse or promote products derived from this software without specific
19 // prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
22 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
24 // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
29 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 #include "misc_log_ex.h"
32 #include "common/perf_timer.h"
33 #include "common/threadpool.h"
34 #include "common/util.h"
35 #include "rctSigs.h"
36 #include "bulletproofs.h"
38 
39 using namespace crypto;
40 using namespace std;
41 
42 #undef ELECTRONEUM_DEFAULT_LOG_CATEGORY
43 #define ELECTRONEUM_DEFAULT_LOG_CATEGORY "ringct"
44 
45 #define CHECK_AND_ASSERT_MES_L1(expr, ret, message) {if(!(expr)) {MCERROR("verify", message); return ret;}}
46 
47 namespace
48 {
49  rct::Bulletproof make_dummy_bulletproof(const std::vector<uint64_t> &outamounts, rct::keyV &C, rct::keyV &masks)
50  {
51  const size_t n_outs = outamounts.size();
52  const rct::key I = rct::identity();
53  size_t nrl = 0;
54  while ((1u << nrl) < n_outs)
55  ++nrl;
56  nrl += 6;
57 
58  C.resize(n_outs);
59  masks.resize(n_outs);
60  for (size_t i = 0; i < n_outs; ++i)
61  {
62  masks[i] = I;
63  rct::key sv8, sv;
64  sv = rct::zero();
65  sv.bytes[0] = outamounts[i] & 255;
66  sv.bytes[1] = (outamounts[i] >> 8) & 255;
67  sv.bytes[2] = (outamounts[i] >> 16) & 255;
68  sv.bytes[3] = (outamounts[i] >> 24) & 255;
69  sv.bytes[4] = (outamounts[i] >> 32) & 255;
70  sv.bytes[5] = (outamounts[i] >> 40) & 255;
71  sv.bytes[6] = (outamounts[i] >> 48) & 255;
72  sv.bytes[7] = (outamounts[i] >> 56) & 255;
73  sc_mul(sv8.bytes, sv.bytes, rct::INV_EIGHT.bytes);
74  rct::addKeys2(C[i], rct::INV_EIGHT, sv8, rct::H);
75  }
76 
77  return rct::Bulletproof{rct::keyV(n_outs, I), I, I, I, I, I, I, rct::keyV(nrl, I), rct::keyV(nrl, I), I, I, I};
78  }
79 }
80 
81 namespace rct {
82  Bulletproof proveRangeBulletproof(keyV &C, keyV &masks, const std::vector<uint64_t> &amounts, epee::span<const key> sk, hw::device &hwdev)
83  {
84  CHECK_AND_ASSERT_THROW_MES(amounts.size() == sk.size(), "Invalid amounts/sk sizes");
85  masks.resize(amounts.size());
86  for (size_t i = 0; i < masks.size(); ++i)
87  masks[i] = hwdev.genCommitmentMask(sk[i]);
88  Bulletproof proof = bulletproof_PROVE(amounts, masks);
89  CHECK_AND_ASSERT_THROW_MES(proof.V.size() == amounts.size(), "V does not have the expected size");
90  C = proof.V;
91  return proof;
92  }
93 
94  bool verBulletproof(const Bulletproof &proof)
95  {
96  try { return bulletproof_VERIFY(proof); }
97  // we can get deep throws from ge_frombytes_vartime if input isn't valid
98  catch (...) { return false; }
99  }
100 
101  bool verBulletproof(const std::vector<const Bulletproof*> &proofs)
102  {
103  try { return bulletproof_VERIFY(proofs); }
104  // we can get deep throws from ge_frombytes_vartime if input isn't valid
105  catch (...) { return false; }
106  }
107 
108  //Borromean (c.f. gmax/andytoshi's paper)
109  boroSig genBorromean(const key64 x, const key64 P1, const key64 P2, const bits indices) {
110  key64 L[2], alpha;
111  key c;
112  int naught = 0, prime = 0, ii = 0, jj=0;
113  boroSig bb;
114  for (ii = 0 ; ii < 64 ; ii++) {
115  naught = indices[ii]; prime = (indices[ii] + 1) % 2;
116  skGen(alpha[ii]);
117  scalarmultBase(L[naught][ii], alpha[ii]);
118  if (naught == 0) {
119  skGen(bb.s1[ii]);
120  c = hash_to_scalar(L[naught][ii]);
121  addKeys2(L[prime][ii], bb.s1[ii], c, P2[ii]);
122  }
123  }
124  bb.ee = hash_to_scalar(L[1]); //or L[1]..
125  key LL, cc;
126  for (jj = 0 ; jj < 64 ; jj++) {
127  if (!indices[jj]) {
128  sc_mulsub(bb.s0[jj].bytes, x[jj].bytes, bb.ee.bytes, alpha[jj].bytes);
129  } else {
130  skGen(bb.s0[jj]);
131  addKeys2(LL, bb.s0[jj], bb.ee, P1[jj]); //different L0
132  cc = hash_to_scalar(LL);
133  sc_mulsub(bb.s1[jj].bytes, x[jj].bytes, cc.bytes, alpha[jj].bytes);
134  }
135  }
136  return bb;
137  }
138 
139  //see above.
140  bool verifyBorromean(const boroSig &bb, const ge_p3 P1[64], const ge_p3 P2[64]) {
141  key64 Lv1; key chash, LL;
142  int ii = 0;
143  ge_p2 p2;
144  for (ii = 0 ; ii < 64 ; ii++) {
145  // equivalent of: addKeys2(LL, bb.s0[ii], bb.ee, P1[ii]);
146  ge_double_scalarmult_base_vartime(&p2, bb.ee.bytes, &P1[ii], bb.s0[ii].bytes);
147  ge_tobytes(LL.bytes, &p2);
148  chash = hash_to_scalar(LL);
149  // equivalent of: addKeys2(Lv1[ii], bb.s1[ii], chash, P2[ii]);
150  ge_double_scalarmult_base_vartime(&p2, chash.bytes, &P2[ii], bb.s1[ii].bytes);
151  ge_tobytes(Lv1[ii].bytes, &p2);
152  }
153  key eeComputed = hash_to_scalar(Lv1); //hash function fine
154  return equalKeys(eeComputed, bb.ee);
155  }
156 
157  bool verifyBorromean(const boroSig &bb, const key64 P1, const key64 P2) {
158  ge_p3 P1_p3[64], P2_p3[64];
159  for (size_t i = 0 ; i < 64 ; ++i) {
160  CHECK_AND_ASSERT_MES_L1(ge_frombytes_vartime(&P1_p3[i], P1[i].bytes) == 0, false, "point conv failed");
161  CHECK_AND_ASSERT_MES_L1(ge_frombytes_vartime(&P2_p3[i], P2[i].bytes) == 0, false, "point conv failed");
162  }
163  return verifyBorromean(bb, P1_p3, P2_p3);
164  }
165 
166  //Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures)
167  //This is a just slghtly more efficient version than the ones described below
168  //(will be explained in more detail in Ring Multisig paper
169  //These are aka MG signatutes in earlier drafts of the ring ct paper
170  // c.f. https://eprint.iacr.org/2015/1098 section 2.
171  // Gen creates a signature which proves that for some column in the keymatrix "pk"
172  // the signer knows a secret key for each row in that column
173  // Ver verifies that the MG sig was created correctly
174  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) {
175  mgSig rv;
176  size_t cols = pk.size();
177  CHECK_AND_ASSERT_THROW_MES(cols >= 2, "Error! What is c if cols = 1!");
178  CHECK_AND_ASSERT_THROW_MES(index < cols, "Index out of range");
179  size_t rows = pk[0].size();
180  CHECK_AND_ASSERT_THROW_MES(rows >= 1, "Empty pk");
181  for (size_t i = 1; i < cols; ++i) {
182  CHECK_AND_ASSERT_THROW_MES(pk[i].size() == rows, "pk is not rectangular");
183  }
184  CHECK_AND_ASSERT_THROW_MES(xx.size() == rows, "Bad xx size");
185  CHECK_AND_ASSERT_THROW_MES(dsRows <= rows, "Bad dsRows size");
186  CHECK_AND_ASSERT_THROW_MES((kLRki && mscout) || (!kLRki && !mscout), "Only one of kLRki/mscout is present");
187  CHECK_AND_ASSERT_THROW_MES(!kLRki || dsRows == 1, "Multisig requires exactly 1 dsRows");
188 
189  size_t i = 0, j = 0, ii = 0;
190  key c, c_old, L, R, Hi;
191  sc_0(c_old.bytes);
192  vector<geDsmp> Ip(dsRows);
193  rv.II = keyV(dsRows);
194  keyV alpha(rows);
195  keyV aG(rows);
196  rv.ss = keyM(cols, aG);
197  keyV aHP(dsRows);
198  keyV toHash(1 + 3 * dsRows + 2 * (rows - dsRows));
199  toHash[0] = message;
200  DP("here1");
201  for (i = 0; i < dsRows; i++) {
202  toHash[3 * i + 1] = pk[index][i];
203  if (kLRki) {
204  // multisig
205  alpha[i] = kLRki->k;
206  toHash[3 * i + 2] = kLRki->L;
207  toHash[3 * i + 3] = kLRki->R;
208  rv.II[i] = kLRki->ki;
209  }
210  else {
211  Hi = hashToPoint(pk[index][i]);
212  hwdev.mlsag_prepare(Hi, xx[i], alpha[i] , aG[i] , aHP[i] , rv.II[i]);
213  toHash[3 * i + 2] = aG[i];
214  toHash[3 * i + 3] = aHP[i];
215  }
216  precomp(Ip[i].k, rv.II[i]);
217  }
218  size_t ndsRows = 3 * dsRows; //non Double Spendable Rows (see identity chains paper)
219  for (i = dsRows, ii = 0 ; i < rows ; i++, ii++) {
220  skpkGen(alpha[i], aG[i]); //need to save alphas for later..
221  toHash[ndsRows + 2 * ii + 1] = pk[index][i];
222  toHash[ndsRows + 2 * ii + 2] = aG[i];
223  }
224 
225  hwdev.mlsag_hash(toHash, c_old);
226 
227 
228  i = (index + 1) % cols;
229  if (i == 0) {
230  copy(rv.cc, c_old);
231  }
232  while (i != index) {
233 
234  rv.ss[i] = skvGen(rows);
235  sc_0(c.bytes);
236  for (j = 0; j < dsRows; j++) {
237  addKeys2(L, rv.ss[i][j], c_old, pk[i][j]);
238  hashToPoint(Hi, pk[i][j]);
239  addKeys3(R, rv.ss[i][j], Hi, c_old, Ip[j].k);
240  toHash[3 * j + 1] = pk[i][j];
241  toHash[3 * j + 2] = L;
242  toHash[3 * j + 3] = R;
243  }
244  for (j = dsRows, ii = 0; j < rows; j++, ii++) {
245  addKeys2(L, rv.ss[i][j], c_old, pk[i][j]);
246  toHash[ndsRows + 2 * ii + 1] = pk[i][j];
247  toHash[ndsRows + 2 * ii + 2] = L;
248  }
249  hwdev.mlsag_hash(toHash, c);
250  copy(c_old, c);
251  i = (i + 1) % cols;
252 
253  if (i == 0) {
254  copy(rv.cc, c_old);
255  }
256  }
257  hwdev.mlsag_sign(c, xx, alpha, rows, dsRows, rv.ss[index]);
258  if (mscout)
259  *mscout = c;
260  return rv;
261  }
262 
263  //Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures)
264  //This is a just slghtly more efficient version than the ones described below
265  //(will be explained in more detail in Ring Multisig paper
266  //These are aka MG signatutes in earlier drafts of the ring ct paper
267  // c.f. https://eprint.iacr.org/2015/1098 section 2.
268  // Gen creates a signature which proves that for some column in the keymatrix "pk"
269  // the signer knows a secret key for each row in that column
270  // Ver verifies that the MG sig was created correctly
271  bool MLSAG_Ver(const key &message, const keyM & pk, const mgSig & rv, size_t dsRows) {
272 
273  size_t cols = pk.size();
274  CHECK_AND_ASSERT_MES(cols >= 2, false, "Error! What is c if cols = 1!");
275  size_t rows = pk[0].size();
276  CHECK_AND_ASSERT_MES(rows >= 1, false, "Empty pk");
277  for (size_t i = 1; i < cols; ++i) {
278  CHECK_AND_ASSERT_MES(pk[i].size() == rows, false, "pk is not rectangular");
279  }
280  CHECK_AND_ASSERT_MES(rv.II.size() == dsRows, false, "Bad II size");
281  CHECK_AND_ASSERT_MES(rv.ss.size() == cols, false, "Bad rv.ss size");
282  for (size_t i = 0; i < cols; ++i) {
283  CHECK_AND_ASSERT_MES(rv.ss[i].size() == rows, false, "rv.ss is not rectangular");
284  }
285  CHECK_AND_ASSERT_MES(dsRows <= rows, false, "Bad dsRows value");
286 
287  for (size_t i = 0; i < rv.ss.size(); ++i)
288  for (size_t j = 0; j < rv.ss[i].size(); ++j)
289  CHECK_AND_ASSERT_MES(sc_check(rv.ss[i][j].bytes) == 0, false, "Bad ss slot");
290  CHECK_AND_ASSERT_MES(sc_check(rv.cc.bytes) == 0, false, "Bad cc");
291 
292  size_t i = 0, j = 0, ii = 0;
293  key c, L, R, Hi;
294  key c_old = copy(rv.cc);
295  vector<geDsmp> Ip(dsRows);
296  for (i = 0 ; i < dsRows ; i++) {
297  precomp(Ip[i].k, rv.II[i]);
298  }
299  size_t ndsRows = 3 * dsRows; //non Double Spendable Rows (see identity chains paper
300  keyV toHash(1 + 3 * dsRows + 2 * (rows - dsRows));
301  toHash[0] = message;
302  i = 0;
303  while (i < cols) {
304  sc_0(c.bytes);
305  for (j = 0; j < dsRows; j++) {
306  addKeys2(L, rv.ss[i][j], c_old, pk[i][j]);
307  hashToPoint(Hi, pk[i][j]);
308  CHECK_AND_ASSERT_MES(!(Hi == rct::identity()), false, "Data hashed to point at infinity");
309  addKeys3(R, rv.ss[i][j], Hi, c_old, Ip[j].k);
310  toHash[3 * j + 1] = pk[i][j];
311  toHash[3 * j + 2] = L;
312  toHash[3 * j + 3] = R;
313  }
314  for (j = dsRows, ii = 0 ; j < rows ; j++, ii++) {
315  addKeys2(L, rv.ss[i][j], c_old, pk[i][j]);
316  toHash[ndsRows + 2 * ii + 1] = pk[i][j];
317  toHash[ndsRows + 2 * ii + 2] = L;
318  }
319  c = hash_to_scalar(toHash);
320  copy(c_old, c);
321  i = (i + 1);
322  }
323  sc_sub(c.bytes, c_old.bytes, rv.cc.bytes);
324  return sc_isnonzero(c.bytes) == 0;
325  }
326 
327 
328 
329  //proveRange and verRange
330  //proveRange gives C, and mask such that \sumCi = C
331  // c.f. https://eprint.iacr.org/2015/1098 section 5.1
332  // and Ci is a commitment to either 0 or 2^i, i=0,...,63
333  // thus this proves that "amount" is in [0, 2^64]
334  // mask is a such that C = aG + bH, and b = amount
335  //verRange verifies that \sum Ci = C and that each Ci is a commitment to 0 or 2^i
336  rangeSig proveRange(key & C, key & mask, const etn_amount & amount) {
337  sc_0(mask.bytes);
338  identity(C);
339  bits b;
340  d2b(b, amount);
341  rangeSig sig;
342  key64 ai;
343  key64 CiH;
344  int i = 0;
345  for (i = 0; i < ATOMS; i++) {
346  skGen(ai[i]);
347  if (b[i] == 0) {
348  scalarmultBase(sig.Ci[i], ai[i]);
349  }
350  if (b[i] == 1) {
351  addKeys1(sig.Ci[i], ai[i], H2[i]);
352  }
353  subKeys(CiH[i], sig.Ci[i], H2[i]);
354  sc_add(mask.bytes, mask.bytes, ai[i].bytes);
355  addKeys(C, C, sig.Ci[i]);
356  }
357  sig.asig = genBorromean(ai, sig.Ci, CiH, b);
358  return sig;
359  }
360 
361  //proveRange and verRange
362  //proveRange gives C, and mask such that \sumCi = C
363  // c.f. https://eprint.iacr.org/2015/1098 section 5.1
364  // and Ci is a commitment to either 0 or 2^i, i=0,...,63
365  // thus this proves that "amount" is in [0, 2^64]
366  // mask is a such that C = aG + bH, and b = amount
367  //verRange verifies that \sum Ci = C and that each Ci is a commitment to 0 or 2^i
368  bool verRange(const key & C, const rangeSig & as) {
369  try
370  {
372  ge_p3 CiH[64], asCi[64];
373  int i = 0;
374  ge_p3 Ctmp_p3 = ge_p3_identity;
375  for (i = 0; i < 64; i++) {
376  // faster equivalent of:
377  // subKeys(CiH[i], as.Ci[i], H2[i]);
378  // addKeys(Ctmp, Ctmp, as.Ci[i]);
379  ge_cached cached;
380  ge_p3 p3;
381  ge_p1p1 p1;
382  CHECK_AND_ASSERT_MES_L1(ge_frombytes_vartime(&p3, H2[i].bytes) == 0, false, "point conv failed");
383  ge_p3_to_cached(&cached, &p3);
384  CHECK_AND_ASSERT_MES_L1(ge_frombytes_vartime(&asCi[i], as.Ci[i].bytes) == 0, false, "point conv failed");
385  ge_sub(&p1, &asCi[i], &cached);
386  ge_p3_to_cached(&cached, &asCi[i]);
387  ge_p1p1_to_p3(&CiH[i], &p1);
388  ge_add(&p1, &Ctmp_p3, &cached);
389  ge_p1p1_to_p3(&Ctmp_p3, &p1);
390  }
391  key Ctmp;
392  ge_p3_tobytes(Ctmp.bytes, &Ctmp_p3);
393  if (!equalKeys(C, Ctmp))
394  return false;
395  if (!verifyBorromean(as.asig, asCi, CiH))
396  return false;
397  return true;
398  }
399  // we can get deep throws from ge_frombytes_vartime if input isn't valid
400  catch (...) { return false; }
401  }
402 
404  {
405  keyV hashes;
406  hashes.reserve(3);
407  hashes.push_back(rv.message);
408  crypto::hash h;
409 
410  std::stringstream ss;
411  binary_archive<true> ba(ss);
412  CHECK_AND_ASSERT_THROW_MES(!rv.mixRing.empty(), "Empty mixRing");
413  const size_t inputs = is_rct_simple(rv.type) ? rv.mixRing.size() : rv.mixRing[0].size();
414  const size_t outputs = rv.ecdhInfo.size();
415  key prehash;
416  CHECK_AND_ASSERT_THROW_MES(const_cast<rctSig&>(rv).serialize_rctsig_base(ba, inputs, outputs),
417  "Failed to serialize rctSigBase");
418  cryptonote::get_blob_hash(ss.str(), h);
419  hashes.push_back(hash2rct(h));
420 
421  keyV kv;
422  if (rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2)
423  {
424  kv.reserve((6*2+9) * rv.p.bulletproofs.size());
425  for (const auto &p: rv.p.bulletproofs)
426  {
427  // V are not hashed as they're expanded from outPk.mask
428  // (and thus hashed as part of rctSigBase above)
429  kv.push_back(p.A);
430  kv.push_back(p.S);
431  kv.push_back(p.T1);
432  kv.push_back(p.T2);
433  kv.push_back(p.taux);
434  kv.push_back(p.mu);
435  for (size_t n = 0; n < p.L.size(); ++n)
436  kv.push_back(p.L[n]);
437  for (size_t n = 0; n < p.R.size(); ++n)
438  kv.push_back(p.R[n]);
439  kv.push_back(p.a);
440  kv.push_back(p.b);
441  kv.push_back(p.t);
442  }
443  }
444  else
445  {
446  kv.reserve((64*3+1) * rv.p.rangeSigs.size());
447  for (const auto &r: rv.p.rangeSigs)
448  {
449  for (size_t n = 0; n < 64; ++n)
450  kv.push_back(r.asig.s0[n]);
451  for (size_t n = 0; n < 64; ++n)
452  kv.push_back(r.asig.s1[n]);
453  kv.push_back(r.asig.ee);
454  for (size_t n = 0; n < 64; ++n)
455  kv.push_back(r.Ci[n]);
456  }
457  }
458  hashes.push_back(cn_fast_hash(kv));
459  hwdev.mlsag_prehash(ss.str(), inputs, outputs, hashes, rv.outPk, prehash);
460  return prehash;
461  }
462 
463  //Ring-ct MG sigs
464  //Prove:
465  // c.f. https://eprint.iacr.org/2015/1098 section 4. definition 10.
466  // This does the MG sig on the "dest" part of the given key matrix, and
467  // the last row is the sum of input commitments from that column - sum output commitments
468  // this shows that sum inputs = sum outputs
469  //Ver:
470  // verifies the above sig is created corretly
471  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) {
472  //setup vars
473  size_t cols = pubs.size();
474  CHECK_AND_ASSERT_THROW_MES(cols >= 1, "Empty pubs");
475  size_t rows = pubs[0].size();
476  CHECK_AND_ASSERT_THROW_MES(rows >= 1, "Empty pubs");
477  for (size_t i = 1; i < cols; ++i) {
478  CHECK_AND_ASSERT_THROW_MES(pubs[i].size() == rows, "pubs is not rectangular");
479  }
480  CHECK_AND_ASSERT_THROW_MES(inSk.size() == rows, "Bad inSk size");
481  CHECK_AND_ASSERT_THROW_MES(outSk.size() == outPk.size(), "Bad outSk/outPk size");
482  CHECK_AND_ASSERT_THROW_MES((kLRki && mscout) || (!kLRki && !mscout), "Only one of kLRki/mscout is present");
483 
484  keyV sk(rows + 1);
485  keyV tmp(rows + 1);
486  size_t i = 0, j = 0;
487  for (i = 0; i < rows + 1; i++) {
488  sc_0(sk[i].bytes);
489  identity(tmp[i]);
490  }
491  keyM M(cols, tmp);
492  //create the matrix to mg sig
493  for (i = 0; i < cols; i++) {
494  M[i][rows] = identity();
495  for (j = 0; j < rows; j++) {
496  M[i][j] = pubs[i][j].dest;
497  addKeys(M[i][rows], M[i][rows], pubs[i][j].mask); //add input commitments in last row
498  }
499  }
500  sc_0(sk[rows].bytes);
501  for (j = 0; j < rows; j++) {
502  sk[j] = copy(inSk[j].dest);
503  sc_add(sk[rows].bytes, sk[rows].bytes, inSk[j].mask.bytes); //add masks in last row
504  }
505  for (i = 0; i < cols; i++) {
506  for (size_t j = 0; j < outPk.size(); j++) {
507  subKeys(M[i][rows], M[i][rows], outPk[j].mask); //subtract output Ci's in last row
508  }
509  //subtract txn fee output in last row
510  subKeys(M[i][rows], M[i][rows], txnFeeKey);
511  }
512  for (size_t j = 0; j < outPk.size(); j++) {
513  sc_sub(sk[rows].bytes, sk[rows].bytes, outSk[j].mask.bytes); //subtract output masks in last row..
514  }
515  mgSig result = MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows, hwdev);
516  memwipe(sk.data(), sk.size() * sizeof(key));
517  return result;
518  }
519 
520 
521  //Ring-ct MG sigs Simple
522  // Simple version for when we assume only
523  // post rct inputs
524  // here pubs is a vector of (P, C) length mixin
525  // inSk is x, a_in corresponding to signing index
526  // a_out, Cout is for the output commitment
527  // index is the signing index..
528  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) {
529  //setup vars
530  size_t rows = 1;
531  size_t cols = pubs.size();
532  CHECK_AND_ASSERT_THROW_MES(cols >= 1, "Empty pubs");
533  CHECK_AND_ASSERT_THROW_MES((kLRki && mscout) || (!kLRki && !mscout), "Only one of kLRki/mscout is present");
534  keyV tmp(rows + 1);
535  keyV sk(rows + 1);
536  size_t i;
537  keyM M(cols, tmp);
538 
539  sk[0] = copy(inSk.dest);
540  sc_sub(sk[1].bytes, inSk.mask.bytes, a.bytes);
541  for (i = 0; i < cols; i++) {
542  M[i][0] = pubs[i].dest;
543  subKeys(M[i][1], pubs[i].mask, Cout);
544  }
545  mgSig result = MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows, hwdev);
546  memwipe(&sk[0], sizeof(key));
547  return result;
548  }
549 
550 
551  //Ring-ct MG sigs
552  //Prove:
553  // c.f. https://eprint.iacr.org/2015/1098 section 4. definition 10.
554  // This does the MG sig on the "dest" part of the given key matrix, and
555  // the last row is the sum of input commitments from that column - sum output commitments
556  // this shows that sum inputs = sum outputs
557  //Ver:
558  // verifies the above sig is created corretly
559  bool verRctMG(const mgSig &mg, const ctkeyM & pubs, const ctkeyV & outPk, const key &txnFeeKey, const key &message) {
561  //setup vars
562  size_t cols = pubs.size();
563  CHECK_AND_ASSERT_MES(cols >= 1, false, "Empty pubs");
564  size_t rows = pubs[0].size();
565  CHECK_AND_ASSERT_MES(rows >= 1, false, "Empty pubs");
566  for (size_t i = 1; i < cols; ++i) {
567  CHECK_AND_ASSERT_MES(pubs[i].size() == rows, false, "pubs is not rectangular");
568  }
569 
570  keyV tmp(rows + 1);
571  size_t i = 0, j = 0;
572  for (i = 0; i < rows + 1; i++) {
573  identity(tmp[i]);
574  }
575  keyM M(cols, tmp);
576 
577  //create the matrix to mg sig
578  for (j = 0; j < rows; j++) {
579  for (i = 0; i < cols; i++) {
580  M[i][j] = pubs[i][j].dest;
581  addKeys(M[i][rows], M[i][rows], pubs[i][j].mask); //add Ci in last row
582  }
583  }
584  for (i = 0; i < cols; i++) {
585  for (j = 0; j < outPk.size(); j++) {
586  subKeys(M[i][rows], M[i][rows], outPk[j].mask); //subtract output Ci's in last row
587  }
588  //subtract txn fee output in last row
589  subKeys(M[i][rows], M[i][rows], txnFeeKey);
590  }
591  return MLSAG_Ver(message, M, mg, rows);
592  }
593 
594  //Ring-ct Simple MG sigs
595  //Ver:
596  //This does a simplified version, assuming only post Rct
597  //inputs
598  bool verRctMGSimple(const key &message, const mgSig &mg, const ctkeyV & pubs, const key & C) {
599  try
600  {
602  //setup vars
603  size_t rows = 1;
604  size_t cols = pubs.size();
605  CHECK_AND_ASSERT_MES(cols >= 1, false, "Empty pubs");
606  keyV tmp(rows + 1);
607  size_t i;
608  keyM M(cols, tmp);
609  ge_p3 Cp3;
610  CHECK_AND_ASSERT_MES_L1(ge_frombytes_vartime(&Cp3, C.bytes) == 0, false, "point conv failed");
611  ge_cached Ccached;
612  ge_p3_to_cached(&Ccached, &Cp3);
613  ge_p1p1 p1;
614  //create the matrix to mg sig
615  for (i = 0; i < cols; i++) {
616  M[i][0] = pubs[i].dest;
617  ge_p3 p3;
618  CHECK_AND_ASSERT_MES_L1(ge_frombytes_vartime(&p3, pubs[i].mask.bytes) == 0, false, "point conv failed");
619  ge_sub(&p1, &p3, &Ccached);
620  ge_p1p1_to_p3(&p3, &p1);
621  ge_p3_tobytes(M[i][1].bytes, &p3);
622  }
623  //DP(C);
624  return MLSAG_Ver(message, M, mg, rows);
625  }
626  catch (...) { return false; }
627  }
628 
629 
630  //These functions get keys from blockchain
631  //replace these when connecting blockchain
632  //getKeyFromBlockchain grabs a key from the blockchain at "reference_index" to mix with
633  //populateFromBlockchain creates a keymatrix with "mixin" columns and one of the columns is inPk
634  // the return value are the key matrix, and the index where inPk was put (random).
635  void getKeyFromBlockchain(ctkey & a, size_t reference_index) {
636  a.mask = pkGen();
637  a.dest = pkGen();
638  }
639 
640  //These functions get keys from blockchain
641  //replace these when connecting blockchain
642  //getKeyFromBlockchain grabs a key from the blockchain at "reference_index" to mix with
643  //populateFromBlockchain creates a keymatrix with "mixin" + 1 columns and one of the columns is inPk
644  // the return value are the key matrix, and the index where inPk was put (random).
645  tuple<ctkeyM, etn_amount> populateFromBlockchain(ctkeyV inPk, int mixin) {
646  int rows = inPk.size();
647  ctkeyM rv(mixin + 1, inPk);
648  int index = randEtnAmount(mixin);
649  int i = 0, j = 0;
650  for (i = 0; i <= mixin; i++) {
651  if (i != index) {
652  for (j = 0; j < rows; j++) {
653  getKeyFromBlockchain(rv[i][j], (size_t)randEtnAmount);
654  }
655  }
656  }
657  return make_tuple(rv, index);
658  }
659 
660  //These functions get keys from blockchain
661  //replace these when connecting blockchain
662  //getKeyFromBlockchain grabs a key from the blockchain at "reference_index" to mix with
663  //populateFromBlockchain creates a keymatrix with "mixin" columns and one of the columns is inPk
664  // the return value are the key matrix, and the index where inPk was put (random).
665  etn_amount populateFromBlockchainSimple(ctkeyV & mixRing, const ctkey & inPk, int mixin) {
666  int index = randEtnAmount(mixin);
667  int i = 0;
668  for (i = 0; i <= mixin; i++) {
669  if (i != index) {
670  getKeyFromBlockchain(mixRing[i], (size_t)randEtnAmount(1000));
671  } else {
672  mixRing[i] = inPk;
673  }
674  }
675  return index;
676  }
677 
678  //RingCT protocol
679  //genRct:
680  // creates an rctSig with all data necessary to verify the rangeProofs and that the signer owns one of the
681  // columns that are claimed as inputs, and that the sum of inputs = sum of outputs.
682  // Also contains masked "amount" and "mask" so the receiver can see how much they received
683  //verRct:
684  // verifies that all signatures (rangeProogs, MG sig, sum inputs = outputs) are correct
685  //decodeRct: (c.f. https://eprint.iacr.org/2015/1098 section 5.1.1)
686  // uses the attached ecdh info to find the amounts represented by each output commitment
687  // must know the destination private key to find the correct amount, else will return a random number
688  // Note: For txn fees, the last index in the amounts vector should contain that
689  // Thus the amounts vector will be "one" longer than the destinations vectort
690  rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<etn_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) {
691  CHECK_AND_ASSERT_THROW_MES(amounts.size() == destinations.size() || amounts.size() == destinations.size() + 1, "Different number of amounts/destinations");
692  CHECK_AND_ASSERT_THROW_MES(amount_keys.size() == destinations.size(), "Different number of amount_keys/destinations");
693  CHECK_AND_ASSERT_THROW_MES(index < mixRing.size(), "Bad index into mixRing");
694  for (size_t n = 0; n < mixRing.size(); ++n) {
695  CHECK_AND_ASSERT_THROW_MES(mixRing[n].size() == inSk.size(), "Bad mixRing size");
696  }
697  CHECK_AND_ASSERT_THROW_MES((kLRki && msout) || (!kLRki && !msout), "Only one of kLRki/msout is present");
698  CHECK_AND_ASSERT_THROW_MES(inSk.size() < 2, "genRct is not suitable for 2+ rings");
699 
700  rctSig rv;
701  rv.type = RCTTypeFull;
702  rv.message = message;
703  rv.outPk.resize(destinations.size());
704  rv.p.rangeSigs.resize(destinations.size());
705  rv.ecdhInfo.resize(destinations.size());
706 
707  size_t i = 0;
708  keyV masks(destinations.size()); //sk mask..
709  outSk.resize(destinations.size());
710  for (i = 0; i < destinations.size(); i++) {
711  //add destination to sig
712  rv.outPk[i].dest = copy(destinations[i]);
713  //compute range proof
714  rv.p.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, amounts[i]);
715  #ifdef DBG
716  CHECK_AND_ASSERT_THROW_MES(verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]), "verRange failed on newly created proof");
717  #endif
718  //mask amount and mask
719  rv.ecdhInfo[i].mask = copy(outSk[i].mask);
720  rv.ecdhInfo[i].amount = d2h(amounts[i]);
721  hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2);
722  }
723 
724  //set txn fee
725  if (amounts.size() > destinations.size())
726  {
727  rv.txnFee = amounts[destinations.size()];
728  }
729  else
730  {
731  rv.txnFee = 0;
732  }
733  key txnFeeKey = scalarmultH(d2h(rv.txnFee));
734 
735  rv.mixRing = mixRing;
736  if (msout)
737  msout->c.resize(1);
738  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));
739  return rv;
740  }
741 
742  rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<etn_amount> & amounts, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, const int mixin, const RCTConfig &rct_config, hw::device &hwdev) {
743  unsigned int index;
744  ctkeyM mixRing;
745  ctkeyV outSk;
746  tie(mixRing, index) = populateFromBlockchain(inPk, mixin);
747  return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, kLRki, msout, index, outSk, rct_config, hwdev);
748  }
749 
750  //RCT simple
751  //for post-rct only
752  rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<etn_amount> &inamounts, const vector<etn_amount> &outamounts, etn_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) {
753  const bool bulletproof = rct_config.range_proof_type != RangeProofBorromean;
754  CHECK_AND_ASSERT_THROW_MES(inamounts.size() > 0, "Empty inamounts");
755  CHECK_AND_ASSERT_THROW_MES(inamounts.size() == inSk.size(), "Different number of inamounts/inSk");
756  CHECK_AND_ASSERT_THROW_MES(outamounts.size() == destinations.size(), "Different number of amounts/destinations");
757  CHECK_AND_ASSERT_THROW_MES(amount_keys.size() == destinations.size(), "Different number of amount_keys/destinations");
758  CHECK_AND_ASSERT_THROW_MES(index.size() == inSk.size(), "Different number of index/inSk");
759  CHECK_AND_ASSERT_THROW_MES(mixRing.size() == inSk.size(), "Different number of mixRing/inSk");
760  for (size_t n = 0; n < mixRing.size(); ++n) {
761  CHECK_AND_ASSERT_THROW_MES(index[n] < mixRing[n].size(), "Bad index into mixRing");
762  }
763  CHECK_AND_ASSERT_THROW_MES((kLRki && msout) || (!kLRki && !msout), "Only one of kLRki/msout is present");
764  if (kLRki && msout) {
765  CHECK_AND_ASSERT_THROW_MES(kLRki->size() == inamounts.size(), "Mismatched kLRki/inamounts sizes");
766  }
767 
768  rctSig rv;
769  rv.type = bulletproof ? (rct_config.bp_version == 0 || rct_config.bp_version >= 2 ? RCTTypeBulletproof2 : RCTTypeBulletproof) : RCTTypeSimple;
770  rv.message = message;
771  rv.outPk.resize(destinations.size());
772  if (!bulletproof)
773  rv.p.rangeSigs.resize(destinations.size());
774  rv.ecdhInfo.resize(destinations.size());
775 
776  size_t i;
777  keyV masks(destinations.size()); //sk mask..
778  outSk.resize(destinations.size());
779  for (i = 0; i < destinations.size(); i++) {
780 
781  //add destination to sig
782  rv.outPk[i].dest = copy(destinations[i]);
783  //compute range proof
784  if (!bulletproof)
785  rv.p.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, outamounts[i]);
786  #ifdef DBG
787  if (!bulletproof)
788  CHECK_AND_ASSERT_THROW_MES(verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]), "verRange failed on newly created proof");
789  #endif
790  }
791 
792  rv.p.bulletproofs.clear();
793  if (bulletproof)
794  {
795  size_t n_amounts = outamounts.size();
796  size_t amounts_proved = 0;
798  {
799  rct::keyV C, masks;
801  {
802  // use a fake bulletproof for speed
803  rv.p.bulletproofs.push_back(make_dummy_bulletproof(outamounts, C, masks));
804  }
805  else
806  {
807  const epee::span<const key> keys{&amount_keys[0], amount_keys.size()};
808  rv.p.bulletproofs.push_back(proveRangeBulletproof(C, masks, outamounts, keys, hwdev));
809  #ifdef DBG
810  CHECK_AND_ASSERT_THROW_MES(verBulletproof(rv.p.bulletproofs.back()), "verBulletproof failed on newly created proof");
811  #endif
812  }
813  for (i = 0; i < outamounts.size(); ++i)
814  {
815  rv.outPk[i].mask = rct::scalarmult8(C[i]);
816  outSk[i].mask = masks[i];
817  }
818  }
819  else while (amounts_proved < n_amounts)
820  {
821  size_t batch_size = 1;
823  while (batch_size * 2 + amounts_proved <= n_amounts && batch_size * 2 <= BULLETPROOF_MAX_OUTPUTS)
824  batch_size *= 2;
825  rct::keyV C, masks;
826  std::vector<uint64_t> batch_amounts(batch_size);
827  for (i = 0; i < batch_size; ++i)
828  batch_amounts[i] = outamounts[i + amounts_proved];
830  {
831  // use a fake bulletproof for speed
832  rv.p.bulletproofs.push_back(make_dummy_bulletproof(batch_amounts, C, masks));
833  }
834  else
835  {
836  const epee::span<const key> keys{&amount_keys[amounts_proved], batch_size};
837  rv.p.bulletproofs.push_back(proveRangeBulletproof(C, masks, batch_amounts, keys, hwdev));
838  #ifdef DBG
839  CHECK_AND_ASSERT_THROW_MES(verBulletproof(rv.p.bulletproofs.back()), "verBulletproof failed on newly created proof");
840  #endif
841  }
842  for (i = 0; i < batch_size; ++i)
843  {
844  rv.outPk[i + amounts_proved].mask = rct::scalarmult8(C[i]);
845  outSk[i + amounts_proved].mask = masks[i];
846  }
847  amounts_proved += batch_size;
848  }
849  }
850 
851  key sumout = zero();
852  for (i = 0; i < outSk.size(); ++i)
853  {
854  sc_add(sumout.bytes, outSk[i].mask.bytes, sumout.bytes);
855 
856  //mask amount and mask
857  rv.ecdhInfo[i].mask = copy(outSk[i].mask);
858  rv.ecdhInfo[i].amount = d2h(outamounts[i]);
859  hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2);
860  }
861 
862  //set txn fee
863  rv.txnFee = txnFee;
864 // TODO: unused ??
865 // key txnFeeKey = scalarmultH(d2h(rv.txnFee));
866  rv.mixRing = mixRing;
867  keyV &pseudoOuts = bulletproof ? rv.p.pseudoOuts : rv.pseudoOuts;
868  pseudoOuts.resize(inamounts.size());
869  rv.p.MGs.resize(inamounts.size());
870  key sumpouts = zero(); //sum pseudoOut masks
871  keyV a(inamounts.size());
872  for (i = 0 ; i < inamounts.size() - 1; i++) {
873  skGen(a[i]);
874  sc_add(sumpouts.bytes, a[i].bytes, sumpouts.bytes);
875  genC(pseudoOuts[i], a[i], inamounts[i]);
876  }
877  sc_sub(a[i].bytes, sumout.bytes, sumpouts.bytes);
878  genC(pseudoOuts[i], a[i], inamounts[i]);
879  DP(pseudoOuts[i]);
880 
881  key full_message = get_pre_mlsag_hash(rv,hwdev);
882  if (msout)
883  msout->c.resize(inamounts.size());
884  for (i = 0 ; i < inamounts.size(); i++) {
885  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);
886  }
887  return rv;
888  }
889 
890  rctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<etn_amount> &inamounts, const vector<etn_amount> &outamounts, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, etn_amount txnFee, unsigned int mixin, const RCTConfig &rct_config, hw::device &hwdev) {
891  std::vector<unsigned int> index;
892  index.resize(inPk.size());
893  ctkeyM mixRing;
894  ctkeyV outSk;
895  mixRing.resize(inPk.size());
896  for (size_t i = 0; i < inPk.size(); ++i) {
897  mixRing[i].resize(mixin+1);
898  index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin);
899  }
900  return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, amount_keys, kLRki, msout, index, outSk, rct_config, hwdev);
901  }
902 
903  //RingCT protocol
904  //genRct:
905  // creates an rctSig with all data necessary to verify the rangeProofs and that the signer owns one of the
906  // columns that are claimed as inputs, and that the sum of inputs = sum of outputs.
907  // Also contains masked "amount" and "mask" so the receiver can see how much they received
908  //verRct:
909  // verifies that all signatures (rangeProogs, MG sig, sum inputs = outputs) are correct
910  //decodeRct: (c.f. https://eprint.iacr.org/2015/1098 section 5.1.1)
911  // uses the attached ecdh info to find the amounts represented by each output commitment
912  // must know the destination private key to find the correct amount, else will return a random number
913  bool verRct(const rctSig & rv, bool semantics) {
915  CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "verRct called on non-full rctSig");
916  if (semantics)
917  {
918  CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs");
919  CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo");
920  CHECK_AND_ASSERT_MES(rv.p.MGs.size() == 1, false, "full rctSig has not one MG");
921  }
922  else
923  {
924  // semantics check is early, we don't have the MGs resolved yet
925  }
926 
927  // some rct ops can throw
928  try
929  {
930  if (semantics) {
933  std::deque<bool> results(rv.outPk.size(), false);
934  DP("range proofs verified?");
935  for (size_t i = 0; i < rv.outPk.size(); i++)
936  tpool.submit(&waiter, [&, i] { results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]); });
937  waiter.wait(&tpool);
938 
939  for (size_t i = 0; i < results.size(); ++i) {
940  if (!results[i]) {
941  LOG_PRINT_L1("Range proof verified failed for proof " << i);
942  return false;
943  }
944  }
945  }
946 
947  if (!semantics) {
948  //compute txn fee
949  key txnFeeKey = scalarmultH(d2h(rv.txnFee));
950  bool mgVerd = verRctMG(rv.p.MGs[0], rv.mixRing, rv.outPk, txnFeeKey, get_pre_mlsag_hash(rv, hw::get_device("default")));
951  DP("mg sig verified?");
952  DP(mgVerd);
953  if (!mgVerd) {
954  LOG_PRINT_L1("MG signature verification failed");
955  return false;
956  }
957  }
958 
959  return true;
960  }
961  catch (const std::exception &e)
962  {
963  LOG_PRINT_L1("Error in verRct: " << e.what());
964  return false;
965  }
966  catch (...)
967  {
968  LOG_PRINT_L1("Error in verRct, but not an actual exception");
969  return false;
970  }
971  }
972 
973  //ver RingCT simple
974  //assumes only post-rct style inputs (at least for max anonymity)
975  bool verRctSemanticsSimple(const std::vector<const rctSig*> & rvv) {
976  try
977  {
979 
982  std::deque<bool> results;
983  std::vector<const Bulletproof*> proofs;
984  size_t max_non_bp_proofs = 0, offset = 0;
985 
986  for (const rctSig *rvp: rvv)
987  {
988  CHECK_AND_ASSERT_MES(rvp, false, "rctSig pointer is NULL");
989  const rctSig &rv = *rvp;
991  false, "verRctSemanticsSimple called on non simple rctSig");
992  const bool bulletproof = is_rct_bulletproof(rv.type);
993  if (bulletproof)
994  {
995  CHECK_AND_ASSERT_MES(rv.outPk.size() == n_bulletproof_amounts(rv.p.bulletproofs), false, "Mismatched sizes of outPk and bulletproofs");
996  CHECK_AND_ASSERT_MES(rv.p.pseudoOuts.size() == rv.p.MGs.size(), false, "Mismatched sizes of rv.p.pseudoOuts and rv.p.MGs");
997  CHECK_AND_ASSERT_MES(rv.pseudoOuts.empty(), false, "rv.pseudoOuts is not empty");
998  }
999  else
1000  {
1001  CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs");
1002  CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.p.MGs.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.p.MGs");
1003  CHECK_AND_ASSERT_MES(rv.p.pseudoOuts.empty(), false, "rv.p.pseudoOuts is not empty");
1004  }
1005  CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo");
1006 
1007  if (!bulletproof)
1008  max_non_bp_proofs += rv.p.rangeSigs.size();
1009  }
1010 
1011  results.resize(max_non_bp_proofs);
1012  for (const rctSig *rvp: rvv)
1013  {
1014  const rctSig &rv = *rvp;
1015 
1016  const bool bulletproof = is_rct_bulletproof(rv.type);
1017  const keyV &pseudoOuts = bulletproof ? rv.p.pseudoOuts : rv.pseudoOuts;
1018 
1019  rct::keyV masks(rv.outPk.size());
1020  for (size_t i = 0; i < rv.outPk.size(); i++) {
1021  masks[i] = rv.outPk[i].mask;
1022  }
1023  key sumOutpks = addKeys(masks);
1024  DP(sumOutpks);
1025  const key txnFeeKey = scalarmultH(d2h(rv.txnFee));
1026  addKeys(sumOutpks, txnFeeKey, sumOutpks);
1027 
1028  key sumPseudoOuts = addKeys(pseudoOuts);
1029  DP(sumPseudoOuts);
1030 
1031  //check pseudoOuts vs Outs..
1032  if (!equalKeys(sumPseudoOuts, sumOutpks)) {
1033  LOG_PRINT_L1("Sum check failed");
1034  return false;
1035  }
1036 
1037  if (bulletproof)
1038  {
1039  for (size_t i = 0; i < rv.p.bulletproofs.size(); i++)
1040  proofs.push_back(&rv.p.bulletproofs[i]);
1041  }
1042  else
1043  {
1044  for (size_t i = 0; i < rv.p.rangeSigs.size(); i++)
1045  tpool.submit(&waiter, [&, i, offset] { results[i+offset] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]); });
1046  offset += rv.p.rangeSigs.size();
1047  }
1048  }
1049  if (!proofs.empty() && !verBulletproof(proofs))
1050  {
1051  LOG_PRINT_L1("Aggregate range proof verified failed");
1052  return false;
1053  }
1054 
1055  waiter.wait(&tpool);
1056  for (size_t i = 0; i < results.size(); ++i) {
1057  if (!results[i]) {
1058  LOG_PRINT_L1("Range proof verified failed for proof " << i);
1059  return false;
1060  }
1061  }
1062 
1063  return true;
1064  }
1065  // we can get deep throws from ge_frombytes_vartime if input isn't valid
1066  catch (const std::exception &e)
1067  {
1068  LOG_PRINT_L1("Error in verRctSemanticsSimple: " << e.what());
1069  return false;
1070  }
1071  catch (...)
1072  {
1073  LOG_PRINT_L1("Error in verRctSemanticsSimple, but not an actual exception");
1074  return false;
1075  }
1076  }
1077 
1079  {
1080  return verRctSemanticsSimple(std::vector<const rctSig*>(1, &rv));
1081  }
1082 
1083  //ver RingCT simple
1084  //assumes only post-rct style inputs (at least for max anonymity)
1086  try
1087  {
1089 
1091  false, "verRctNonSemanticsSimple called on non simple rctSig");
1092  const bool bulletproof = is_rct_bulletproof(rv.type);
1093  // semantics check is early, and mixRing/MGs aren't resolved yet
1094  if (bulletproof)
1095  CHECK_AND_ASSERT_MES(rv.p.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.p.pseudoOuts and mixRing");
1096  else
1097  CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.pseudoOuts and mixRing");
1098 
1099  const size_t threads = std::max(rv.outPk.size(), rv.mixRing.size());
1100 
1101  std::deque<bool> results(threads);
1104 
1105  const keyV &pseudoOuts = bulletproof ? rv.p.pseudoOuts : rv.pseudoOuts;
1106 
1107  const key message = get_pre_mlsag_hash(rv, hw::get_device("default"));
1108 
1109  results.clear();
1110  results.resize(rv.mixRing.size());
1111  for (size_t i = 0 ; i < rv.mixRing.size() ; i++) {
1112  tpool.submit(&waiter, [&, i] {
1113  results[i] = verRctMGSimple(message, rv.p.MGs[i], rv.mixRing[i], pseudoOuts[i]);
1114  });
1115  }
1116  waiter.wait(&tpool);
1117 
1118  for (size_t i = 0; i < results.size(); ++i) {
1119  if (!results[i]) {
1120  LOG_PRINT_L1("verRctMGSimple failed for input " << i);
1121  return false;
1122  }
1123  }
1124 
1125  return true;
1126  }
1127  // we can get deep throws from ge_frombytes_vartime if input isn't valid
1128  catch (const std::exception &e)
1129  {
1130  LOG_PRINT_L1("Error in verRctNonSemanticsSimple: " << e.what());
1131  return false;
1132  }
1133  catch (...)
1134  {
1135  LOG_PRINT_L1("Error in verRctNonSemanticsSimple, but not an actual exception");
1136  return false;
1137  }
1138  }
1139 
1140  //RingCT protocol
1141  //genRct:
1142  // creates an rctSig with all data necessary to verify the rangeProofs and that the signer owns one of the
1143  // columns that are claimed as inputs, and that the sum of inputs = sum of outputs.
1144  // Also contains masked "amount" and "mask" so the receiver can see how much they received
1145  //verRct:
1146  // verifies that all signatures (rangeProogs, MG sig, sum inputs = outputs) are correct
1147  //decodeRct: (c.f. https://eprint.iacr.org/2015/1098 section 5.1.1)
1148  // uses the attached ecdh info to find the amounts represented by each output commitment
1149  // must know the destination private key to find the correct amount, else will return a random number
1150  etn_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask, hw::device &hwdev) {
1151  CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "decodeRct called on non-full rctSig");
1152  CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index");
1153  CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo");
1154 
1155  //mask amount and mask
1156  ecdhTuple ecdh_info = rv.ecdhInfo[i];
1157  hwdev.ecdhDecode(ecdh_info, sk, rv.type == RCTTypeBulletproof2);
1158  mask = ecdh_info.mask;
1159  key amount = ecdh_info.amount;
1160  key C = rv.outPk[i].mask;
1161  DP("C");
1162  DP(C);
1163  key Ctmp;
1164  CHECK_AND_ASSERT_THROW_MES(sc_check(mask.bytes) == 0, "warning, bad ECDH mask");
1165  CHECK_AND_ASSERT_THROW_MES(sc_check(amount.bytes) == 0, "warning, bad ECDH amount");
1166  addKeys2(Ctmp, mask, amount, H);
1167  DP("Ctmp");
1168  DP(Ctmp);
1169  if (equalKeys(C, Ctmp) == false) {
1170  CHECK_AND_ASSERT_THROW_MES(false, "warning, amount decoded incorrectly, will be unable to spend");
1171  }
1172  return h2d(amount);
1173  }
1174 
1175  etn_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, hw::device &hwdev) {
1176  key mask;
1177  return decodeRct(rv, sk, i, mask, hwdev);
1178  }
1179 
1180  etn_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask, hw::device &hwdev) {
1181  CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2, false, "decodeRct called on non simple rctSig");
1182  CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index");
1183  CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo");
1184 
1185  //mask amount and mask
1186  ecdhTuple ecdh_info = rv.ecdhInfo[i];
1187  hwdev.ecdhDecode(ecdh_info, sk, rv.type == RCTTypeBulletproof2);
1188  mask = ecdh_info.mask;
1189  key amount = ecdh_info.amount;
1190  key C = rv.outPk[i].mask;
1191  DP("C");
1192  DP(C);
1193  key Ctmp;
1194  CHECK_AND_ASSERT_THROW_MES(sc_check(mask.bytes) == 0, "warning, bad ECDH mask");
1195  CHECK_AND_ASSERT_THROW_MES(sc_check(amount.bytes) == 0, "warning, bad ECDH amount");
1196  addKeys2(Ctmp, mask, amount, H);
1197  DP("Ctmp");
1198  DP(Ctmp);
1199  if (equalKeys(C, Ctmp) == false) {
1200  CHECK_AND_ASSERT_THROW_MES(false, "warning, amount decoded incorrectly, will be unable to spend");
1201  }
1202  return h2d(amount);
1203  }
1204 
1205  etn_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, hw::device &hwdev) {
1206  key mask;
1207  return decodeRctSimple(rv, sk, i, mask, hwdev);
1208  }
1209 
1210  bool signMultisig(rctSig &rv, const std::vector<unsigned int> &indices, const keyV &k, const multisig_out &msout, const key &secret_key) {
1212  false, "unsupported rct type");
1213  CHECK_AND_ASSERT_MES(indices.size() == k.size(), false, "Mismatched k/indices sizes");
1214  CHECK_AND_ASSERT_MES(k.size() == rv.p.MGs.size(), false, "Mismatched k/MGs size");
1215  CHECK_AND_ASSERT_MES(k.size() == msout.c.size(), false, "Mismatched k/msout.c size");
1216  if (rv.type == RCTTypeFull)
1217  {
1218  CHECK_AND_ASSERT_MES(rv.p.MGs.size() == 1, false, "MGs not a single element");
1219  }
1220  for (size_t n = 0; n < indices.size(); ++n) {
1221  CHECK_AND_ASSERT_MES(indices[n] < rv.p.MGs[n].ss.size(), false, "Index out of range");
1222  CHECK_AND_ASSERT_MES(!rv.p.MGs[n].ss[indices[n]].empty(), false, "empty ss line");
1223  }
1224 
1225  for (size_t n = 0; n < indices.size(); ++n) {
1226  rct::key diff;
1227  sc_mulsub(diff.bytes, msout.c[n].bytes, secret_key.bytes, k[n].bytes);
1228  sc_add(rv.p.MGs[n].ss[indices[n]][0].bytes, rv.p.MGs[n].ss[indices[n]][0].bytes, diff.bytes);
1229  }
1230  return true;
1231  }
1232 }
keyV skvGen(size_t rows)
Definition: rctOps.cpp:266
#define CHECK_AND_ASSERT_THROW_MES(expr, message)
Definition: misc_log_ex.h:173
etn_amount txnFee
Definition: rctTypes.h:248
keyM ss
Definition: rctTypes.h:153
boroSig genBorromean(const key64 x, const key64 P1, const key64 P2, const bits indices)
Definition: rctSigs.cpp:109
etn_amount h2d(const key &test)
Definition: rctTypes.cpp:161
etn_amount populateFromBlockchainSimple(ctkeyV &mixRing, const ctkey &inPk, int mixin)
Definition: rctSigs.cpp:665
void precomp(ge_dsmp rv, const key &B)
Definition: rctOps.cpp:476
void addKeys1(key &aGB, const key &a, const key &B)
Definition: rctOps.cpp:459
key pkGen()
Definition: rctOps.cpp:277
void d2h(key &amounth, const etn_amount in)
Definition: rctTypes.cpp:119
#define PERF_TIMER(name)
Definition: perf_timer.h:82
#define LOG_PRINT_L1(x)
Definition: misc_log_ex.h:100
virtual rct::key genCommitmentMask(const rct::key &amount_key)=0
void get_blob_hash(const epee::span< const char > &blob, crypto::hash &res)
std::vector< mgSig > MGs
Definition: rctTypes.h:321
CXA_THROW_INFO_T void(* dest)(void *))
Definition: stack_trace.cpp:91
A global thread pool.
Definition: threadpool.h:43
void addKeys3(key &aAbB, const key &a, const key &A, const key &b, const ge_dsmp B)
Definition: rctOps.cpp:485
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
Definition: misc_log_ex.h:181
crypto::hash chash
Definition: main.cpp:47
virtual bool mlsag_prepare(const rct::key &H, const rct::key &xx, rct::key &a, rct::key &aG, rct::key &aHP, rct::key &rvII)=0
void sc_mul(unsigned char *, const unsigned char *, const unsigned char *)
bool bulletproof_VERIFY(const Bulletproof &proof)
key get_pre_mlsag_hash(const rctSig &rv, hw::device &hwdev)
Definition: rctSigs.cpp:403
void sc_0(unsigned char *)
std::vector< rangeSig > rangeSigs
Definition: rctTypes.h:319
virtual bool ecdhEncode(rct::ecdhTuple &unmasked, const rct::key &sharedSec, bool short_amount)=0
bool is_rct_simple(int type)
Definition: rctTypes.cpp:214
bool verRct(const rctSig &rv, bool semantics)
Definition: rctSigs.cpp:913
const char * key
Definition: hmac_keccak.cpp:39
crypto namespace.
Definition: crypto.cpp:58
#define BULLETPROOF_MAX_OUTPUTS
STL namespace.
Non-owning sequence of data. Does not deep copy.
Definition: span.h:56
public_key addKeys(const public_key &A, const public_key &B)
Definition: crypto.h:339
void d2b(bits amountb, etn_amount val)
Definition: rctTypes.cpp:145
void ge_p3_tobytes(unsigned char *, const ge_p3 *)
void getKeyFromBlockchain(ctkey &a, size_t reference_index)
Definition: rctSigs.cpp:635
virtual device_mode get_mode() const
Definition: device.hpp:131
static threadpool & getInstance()
Definition: threadpool.h:46
key dest
Definition: rctTypes.h:97
uint8_t type
Definition: rctTypes.h:241
struct hash_func hashes[]
#define CHECK_AND_ASSERT_MES_L1(expr, ret, message)
Definition: rctSigs.cpp:45
#define ATOMS
Definition: rctTypes.h:65
void copy(key &AA, const key &A)
Definition: rctOps.h:79
tuple make_tuple()
Definition: gtest-tuple.h:675
std::vector< key > keyV
Definition: rctTypes.h:88
key64 s0
Definition: rctTypes.h:140
std::vector< ecdhTuple > ecdhInfo
Definition: rctTypes.h:246
bool is_rct_bulletproof(int type)
Definition: rctTypes.cpp:227
constexpr std::size_t size() const noexcept
Definition: span.h:111
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)
Definition: rctSigs.cpp:528
int sc_check(const unsigned char *)
etn_amount decodeRctSimple(const rctSig &rv, const key &sk, unsigned int i, hw::device &hwdev)
Definition: rctSigs.cpp:1205
uint64_t etn_amount
Definition: rctTypes.h:135
void wait(threadpool *tpool)
Definition: threadpool.cpp:115
virtual bool mlsag_prehash(const std::string &blob, size_t inputs_size, size_t outputs_size, const rct::keyV &hashes, const rct::ctkeyV &outPk, rct::key &prehash)=0
void ge_p3_to_cached(ge_cached *, const ge_p3 *)
rctSigPrunable p
Definition: rctTypes.h:437
key key64[64]
Definition: rctTypes.h:137
etn_amount decodeRct(const rctSig &rv, const key &sk, unsigned int i, hw::device &hwdev)
Definition: rctSigs.cpp:1175
void sc_mulsub(unsigned char *, const unsigned char *, const unsigned char *, const unsigned char *)
device & get_device(const std::string &device_descriptor)
Definition: device.cpp:95
std::vector< ctkey > ctkeyV
Definition: rctTypes.h:100
boroSig asig
Definition: rctTypes.h:170
void sc_add(unsigned char *, const unsigned char *, const unsigned char *)
bool MLSAG_Ver(const key &message, const keyM &pk, const mgSig &rv, size_t dsRows)
Definition: rctSigs.cpp:271
tuple< ctkeyM, etn_amount > populateFromBlockchain(ctkeyV inPk, int mixin)
Definition: rctSigs.cpp:645
key scalarmultH(const key &a)
Definition: rctOps.cpp:389
keyV II
Definition: rctTypes.h:155
Bulletproof proveRangeBulletproof(keyV &C, keyV &masks, const std::vector< uint64_t > &amounts, epee::span< const key > sk, hw::device &hwdev)
Definition: rctSigs.cpp:82
void ge_double_scalarmult_base_vartime(ge_p2 *, const unsigned char *, const ge_p3 *, const unsigned char *)
bool signMultisig(rctSig &rv, const std::vector< unsigned int > &indices, const keyV &k, const multisig_out &msout, const key &secret_key)
Definition: rctSigs.cpp:1210
void ge_tobytes(unsigned char *, const ge_p2 *)
#define DP(x)
Definition: rctOps.h:55
void cn_fast_hash(const void *data, size_t length, char *hash)
void skGen(key &sk)
Definition: rctOps.cpp:253
std::string message("Message requiring signing")
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)
Definition: rctSigs.cpp:471
etn_amount randEtnAmount(etn_amount upperlimit)
Definition: rctOps.cpp:343
virtual bool mlsag_hash(const rct::keyV &long_message, rct::key &c)=0
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition: pointer.h:1124
void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q)
std::vector< key > c
Definition: rctTypes.h:112
void scalarmultBase(key &aG, const key &a)
Definition: rctOps.cpp:350
void ge_p1p1_to_p3(ge_p3 *, const ge_p1p1 *)
std::vector< keyV > keyM
Definition: rctTypes.h:89
void ge_add(ge_p1p1 *, const ge_p3 *, const ge_cached *)
void submit(waiter *waiter, std::function< void()> f, bool leaf=false)
Definition: threadpool.cpp:69
unsigned char bytes[32]
Definition: rctTypes.h:86
key identity()
Definition: rctOps.h:73
rangeSig proveRange(key &C, key &mask, const etn_amount &amount)
Definition: rctSigs.cpp:336
key64 s1
Definition: rctTypes.h:141
const ge_p3 ge_p3_identity
ctkeyV outPk
Definition: rctTypes.h:247
void subKeys(key &AB, const key &A, const key &B)
Definition: rctOps.cpp:505
void addKeys2(key &aGbB, const key &a, const key &b, const key &B)
Definition: rctOps.cpp:466
void skpkGen(key &sk, key &pk)
Definition: rctOps.cpp:284
bool verRctMG(const mgSig &mg, const ctkeyM &pubs, const ctkeyV &outPk, const key &txnFeeKey, const key &message)
Definition: rctSigs.cpp:559
bool verRctMGSimple(const key &message, const mgSig &mg, const ctkeyV &pubs, const key &C)
Definition: rctSigs.cpp:598
key mask
Definition: rctTypes.h:98
key scalarmult8(const key &P)
Definition: rctOps.cpp:398
bool verRange(const key &C, const rangeSig &as)
Definition: rctSigs.cpp:368
int ge_frombytes_vartime(ge_p3 *, const unsigned char *)
void hash_to_scalar(const void *data, size_t length, ec_scalar &res)
Definition: crypto.cpp:126
void sc_sub(unsigned char *, const unsigned char *, const unsigned char *)
bool verRctNonSemanticsSimple(const rctSig &rv)
Definition: rctSigs.cpp:1085
key hashToPoint(const key &hh)
Definition: rctOps.cpp:638
RangeProofType range_proof_type
Definition: rctTypes.h:237
POD_CLASS hash
Definition: hash.h:50
std::vector< ctkeyV > ctkeyM
Definition: rctTypes.h:101
void * memwipe(void *src, size_t n)
virtual bool mlsag_sign(const rct::key &c, const rct::keyV &xx, const rct::keyV &alpha, const size_t rows, const size_t dsRows, rct::keyV &ss)=0
bool equalKeys(const key &a, const key &b)
Definition: rctOps.cpp:519
key zero()
Definition: rctOps.h:70
bool verifyBorromean(const boroSig &bb, const key64 P1, const key64 P2)
Definition: rctSigs.cpp:157
bool verBulletproof(const std::vector< const Bulletproof *> &proofs)
Definition: rctSigs.cpp:101
std::vector< Bulletproof > bulletproofs
Definition: rctTypes.h:320
void genC(key &C, const key &a, etn_amount amount)
Definition: rctOps.cpp:297
unsigned int bits[ATOMS]
Definition: rctTypes.h:136
bool verRctSemanticsSimple(const rctSig &rv)
Definition: rctSigs.cpp:1078
ctkeyM mixRing
Definition: rctTypes.h:243
rctSig genRctSimple(const key &message, const ctkeyV &inSk, const ctkeyV &inPk, const keyV &destinations, const vector< etn_amount > &inamounts, const vector< etn_amount > &outamounts, const keyV &amount_keys, const std::vector< multisig_kLRki > *kLRki, multisig_out *msout, etn_amount txnFee, unsigned int mixin, const RCTConfig &rct_config, hw::device &hwdev)
Definition: rctSigs.cpp:890
int sc_isnonzero(const unsigned char *)
rctSig genRct(const key &message, const ctkeyV &inSk, const ctkeyV &inPk, const keyV &destinations, const vector< etn_amount > &amounts, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, const int mixin, const RCTConfig &rct_config, hw::device &hwdev)
Definition: rctSigs.cpp:742
Bulletproof bulletproof_PROVE(const rct::key &v, const rct::key &gamma)
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)
Definition: rctSigs.cpp:174
int rows
Definition: crypto.h:86
virtual bool ecdhDecode(rct::ecdhTuple &masked, const rct::key &sharedSec, bool short_amount)=0
size_t n_bulletproof_amounts(const Bulletproof &proof)
Definition: rctTypes.cpp:251
rct::keyV V
Definition: rctTypes.h:181