42 #undef ELECTRONEUM_DEFAULT_LOG_CATEGORY 43 #define ELECTRONEUM_DEFAULT_LOG_CATEGORY "ringct" 45 #define CHECK_AND_ASSERT_MES_L1(expr, ret, message) {if(!(expr)) {MCERROR("verify", message); return ret;}} 51 const size_t n_outs = outamounts.size();
54 while ((1u << nrl) < n_outs)
60 for (
size_t i = 0; i < n_outs; ++i)
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;
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};
85 masks.resize(amounts.size());
86 for (
size_t i = 0; i < masks.size(); ++i)
98 catch (...) {
return false; }
105 catch (...) {
return false; }
112 int naught = 0, prime = 0, ii = 0, jj=0;
114 for (ii = 0 ; ii < 64 ; ii++) {
115 naught = indices[ii]; prime = (indices[ii] + 1) % 2;
126 for (jj = 0 ; jj < 64 ; jj++) {
144 for (ii = 0 ; ii < 64 ; ii++) {
158 ge_p3 P1_p3[64], P2_p3[64];
159 for (
size_t i = 0 ; i < 64 ; ++i) {
176 size_t cols = pk.size();
179 size_t rows = pk[0].size();
181 for (
size_t i = 1; i < cols; ++i) {
189 size_t i = 0, j = 0, ii = 0;
190 key c, c_old, L, R, Hi;
192 vector<geDsmp> Ip(dsRows);
198 keyV toHash(1 + 3 * dsRows + 2 * (
rows - dsRows));
201 for (i = 0; i < dsRows; i++) {
202 toHash[3 * i + 1] = pk[index][i];
206 toHash[3 * i + 2] = kLRki->
L;
207 toHash[3 * i + 3] = kLRki->
R;
208 rv.
II[i] = kLRki->
ki;
213 toHash[3 * i + 2] = aG[i];
214 toHash[3 * i + 3] = aHP[i];
218 size_t ndsRows = 3 * dsRows;
219 for (i = dsRows, ii = 0 ; i <
rows ; i++, ii++) {
221 toHash[ndsRows + 2 * ii + 1] = pk[index][i];
222 toHash[ndsRows + 2 * ii + 2] = aG[i];
228 i = (index + 1) % cols;
236 for (j = 0; j < dsRows; j++) {
240 toHash[3 * j + 1] = pk[i][j];
241 toHash[3 * j + 2] = L;
242 toHash[3 * j + 3] = R;
244 for (j = dsRows, ii = 0; j <
rows; j++, ii++) {
246 toHash[ndsRows + 2 * ii + 1] = pk[i][j];
247 toHash[ndsRows + 2 * ii + 2] = L;
273 size_t cols = pk.size();
275 size_t rows = pk[0].size();
277 for (
size_t i = 1; i < cols; ++i) {
282 for (
size_t i = 0; i < cols; ++i) {
287 for (
size_t i = 0; i < rv.
ss.size(); ++i)
288 for (
size_t j = 0; j < rv.
ss[i].size(); ++j)
292 size_t i = 0, j = 0, ii = 0;
295 vector<geDsmp> Ip(dsRows);
296 for (i = 0 ; i < dsRows ; i++) {
299 size_t ndsRows = 3 * dsRows;
300 keyV toHash(1 + 3 * dsRows + 2 * (
rows - dsRows));
305 for (j = 0; j < dsRows; j++) {
310 toHash[3 * j + 1] = pk[i][j];
311 toHash[3 * j + 2] = L;
312 toHash[3 * j + 3] = R;
314 for (j = dsRows, ii = 0 ; j <
rows ; j++, ii++) {
316 toHash[ndsRows + 2 * ii + 1] = pk[i][j];
317 toHash[ndsRows + 2 * ii + 2] = L;
345 for (i = 0; i <
ATOMS; i++) {
372 ge_p3 CiH[64], asCi[64];
375 for (i = 0; i < 64; i++) {
385 ge_sub(&p1, &asCi[i], &cached);
388 ge_add(&p1, &Ctmp_p3, &cached);
400 catch (...) {
return false; }
410 std::stringstream ss;
414 const size_t outputs = rv.
ecdhInfo.size();
417 "Failed to serialize rctSigBase");
419 hashes.push_back(hash2rct(h));
433 kv.push_back(p.taux);
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]);
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]);
473 size_t cols = pubs.size();
475 size_t rows = pubs[0].size();
477 for (
size_t i = 1; i < cols; ++i) {
487 for (i = 0; i <
rows + 1; i++) {
493 for (i = 0; i < cols; i++) {
495 for (j = 0; j <
rows; j++) {
496 M[i][j] = pubs[i][j].dest;
501 for (j = 0; j <
rows; j++) {
505 for (i = 0; i < cols; i++) {
506 for (
size_t j = 0; j < outPk.size(); j++) {
512 for (
size_t j = 0; j < outPk.size(); j++) {
531 size_t cols = pubs.size();
541 for (i = 0; i < cols; i++) {
542 M[i][0] = pubs[i].dest;
543 subKeys(M[i][1], pubs[i].mask, Cout);
562 size_t cols = pubs.size();
564 size_t rows = pubs[0].size();
566 for (
size_t i = 1; i < cols; ++i) {
572 for (i = 0; i <
rows + 1; i++) {
578 for (j = 0; j <
rows; j++) {
579 for (i = 0; i < cols; i++) {
580 M[i][j] = pubs[i][j].dest;
584 for (i = 0; i < cols; i++) {
585 for (j = 0; j < outPk.size(); j++) {
604 size_t cols = pubs.size();
615 for (i = 0; i < cols; i++) {
616 M[i][0] = pubs[i].dest;
619 ge_sub(&p1, &p3, &Ccached);
626 catch (...) {
return false; }
646 int rows = inPk.size();
647 ctkeyM rv(mixin + 1, inPk);
650 for (i = 0; i <= mixin; i++) {
652 for (j = 0; j <
rows; j++) {
668 for (i = 0; i <= mixin; i++) {
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");
694 for (
size_t n = 0; n < mixRing.size(); ++n) {
703 rv.outPk.resize(destinations.size());
704 rv.p.rangeSigs.resize(destinations.size());
705 rv.ecdhInfo.resize(destinations.size());
708 keyV masks(destinations.size());
709 outSk.resize(destinations.size());
710 for (i = 0; i < destinations.size(); i++) {
712 rv.outPk[i].dest =
copy(destinations[i]);
714 rv.p.rangeSigs[i] =
proveRange(rv.outPk[i].mask, outSk[i].mask, amounts[i]);
719 rv.ecdhInfo[i].mask =
copy(outSk[i].mask);
720 rv.ecdhInfo[i].amount =
d2h(amounts[i]);
725 if (amounts.size() > destinations.size())
727 rv.txnFee = amounts[destinations.size()];
735 rv.mixRing = mixRing;
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));
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) {
747 return genRct(
message, inSk, destinations, amounts, mixRing, amount_keys, kLRki, msout, index, outSk, rct_config, hwdev);
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) {
760 for (
size_t n = 0; n < mixRing.size(); ++n) {
764 if (kLRki && msout) {
771 rv.
outPk.resize(destinations.size());
774 rv.
ecdhInfo.resize(destinations.size());
777 keyV masks(destinations.size());
778 outSk.resize(destinations.size());
779 for (i = 0; i < destinations.size(); i++) {
782 rv.
outPk[i].dest =
copy(destinations[i]);
795 size_t n_amounts = outamounts.size();
796 size_t amounts_proved = 0;
803 rv.
p.
bulletproofs.push_back(make_dummy_bulletproof(outamounts, C, masks));
813 for (i = 0; i < outamounts.size(); ++i)
816 outSk[i].mask = masks[i];
819 else while (amounts_proved < n_amounts)
821 size_t batch_size = 1;
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];
832 rv.
p.
bulletproofs.push_back(make_dummy_bulletproof(batch_amounts, C, masks));
842 for (i = 0; i < batch_size; ++i)
845 outSk[i + amounts_proved].mask = masks[i];
847 amounts_proved += batch_size;
852 for (i = 0; i < outSk.size(); ++i)
868 pseudoOuts.resize(inamounts.size());
869 rv.
p.
MGs.resize(inamounts.size());
871 keyV a(inamounts.size());
872 for (i = 0 ; i < inamounts.size() - 1; i++) {
875 genC(pseudoOuts[i],
a[i], inamounts[i]);
878 genC(pseudoOuts[i],
a[i], inamounts[i]);
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);
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());
895 mixRing.resize(inPk.size());
896 for (
size_t i = 0; i < inPk.size(); ++i) {
897 mixRing[i].resize(mixin+1);
900 return genRctSimple(
message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, amount_keys, kLRki, msout, index, outSk, rct_config, hwdev);
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]); });
939 for (
size_t i = 0; i < results.size(); ++i) {
941 LOG_PRINT_L1(
"Range proof verified failed for proof " << i);
951 DP(
"mg sig verified?");
961 catch (
const std::exception &e)
968 LOG_PRINT_L1(
"Error in verRct, but not an actual exception");
982 std::deque<bool> results;
983 std::vector<const Bulletproof*> proofs;
984 size_t max_non_bp_proofs = 0, offset = 0;
986 for (
const rctSig *rvp: rvv)
991 false,
"verRctSemanticsSimple called on non simple rctSig");
1011 results.resize(max_non_bp_proofs);
1012 for (
const rctSig *rvp: rvv)
1020 for (
size_t i = 0; i < rv.
outPk.size(); i++) {
1021 masks[i] = rv.
outPk[i].mask;
1026 addKeys(sumOutpks, txnFeeKey, sumOutpks);
1032 if (!
equalKeys(sumPseudoOuts, sumOutpks)) {
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]); });
1055 waiter.
wait(&tpool);
1056 for (
size_t i = 0; i < results.size(); ++i) {
1058 LOG_PRINT_L1(
"Range proof verified failed for proof " << i);
1066 catch (
const std::exception &e)
1068 LOG_PRINT_L1(
"Error in verRctSemanticsSimple: " << e.what());
1073 LOG_PRINT_L1(
"Error in verRctSemanticsSimple, but not an actual exception");
1091 false,
"verRctNonSemanticsSimple called on non simple rctSig");
1099 const size_t threads = std::max(rv.
outPk.size(), rv.
mixRing.size());
1101 std::deque<bool> results(threads);
1110 results.resize(rv.
mixRing.size());
1111 for (
size_t i = 0 ; i < rv.
mixRing.size() ; i++) {
1112 tpool.
submit(&waiter, [&, i] {
1116 waiter.
wait(&tpool);
1118 for (
size_t i = 0; i < results.size(); ++i) {
1128 catch (
const std::exception &e)
1130 LOG_PRINT_L1(
"Error in verRctNonSemanticsSimple: " << e.what());
1135 LOG_PRINT_L1(
"Error in verRctNonSemanticsSimple, but not an actual exception");
1158 mask = ecdh_info.mask;
1159 key amount = ecdh_info.amount;
1177 return decodeRct(rv, sk, i, mask, hwdev);
1188 mask = ecdh_info.mask;
1189 key amount = ecdh_info.amount;
1212 false,
"unsupported rct type");
1220 for (
size_t n = 0; n < indices.size(); ++n) {
1225 for (
size_t n = 0; n < indices.size(); ++n) {
1228 sc_add(rv.
p.
MGs[n].ss[indices[n]][0].bytes, rv.
p.
MGs[n].ss[indices[n]][0].bytes, diff.
bytes);
#define CHECK_AND_ASSERT_THROW_MES(expr, message)
boroSig genBorromean(const key64 x, const key64 P1, const key64 P2, const bits indices)
etn_amount h2d(const key &test)
etn_amount populateFromBlockchainSimple(ctkeyV &mixRing, const ctkey &inPk, int mixin)
void precomp(ge_dsmp rv, const key &B)
void addKeys1(key &aGB, const key &a, const key &B)
void d2h(key &amounth, const etn_amount in)
virtual rct::key genCommitmentMask(const rct::key &amount_key)=0
void get_blob_hash(const epee::span< const char > &blob, crypto::hash &res)
CXA_THROW_INFO_T void(* dest)(void *))
void addKeys3(key &aAbB, const key &a, const key &A, const key &b, const ge_dsmp B)
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
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)
void sc_0(unsigned char *)
std::vector< rangeSig > rangeSigs
virtual bool ecdhEncode(rct::ecdhTuple &unmasked, const rct::key &sharedSec, bool short_amount)=0
bool is_rct_simple(int type)
bool verRct(const rctSig &rv, bool semantics)
#define BULLETPROOF_MAX_OUTPUTS
Non-owning sequence of data. Does not deep copy.
public_key addKeys(const public_key &A, const public_key &B)
void d2b(bits amountb, etn_amount val)
void ge_p3_tobytes(unsigned char *, const ge_p3 *)
void getKeyFromBlockchain(ctkey &a, size_t reference_index)
virtual device_mode get_mode() const
struct hash_func hashes[]
#define CHECK_AND_ASSERT_MES_L1(expr, ret, message)
void copy(key &AA, const key &A)
std::vector< ecdhTuple > ecdhInfo
bool is_rct_bulletproof(int type)
constexpr std::size_t size() const noexcept
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)
int sc_check(const unsigned char *)
etn_amount decodeRctSimple(const rctSig &rv, const key &sk, unsigned int i, hw::device &hwdev)
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 *)
etn_amount decodeRct(const rctSig &rv, const key &sk, unsigned int i, hw::device &hwdev)
void sc_mulsub(unsigned char *, const unsigned char *, const unsigned char *, const unsigned char *)
device & get_device(const std::string &device_descriptor)
std::vector< ctkey > ctkeyV
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)
tuple< ctkeyM, etn_amount > populateFromBlockchain(ctkeyV inPk, int mixin)
key scalarmultH(const key &a)
Bulletproof proveRangeBulletproof(keyV &C, keyV &masks, const std::vector< uint64_t > &amounts, epee::span< const key > sk, hw::device &hwdev)
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)
void ge_tobytes(unsigned char *, const ge_p2 *)
void cn_fast_hash(const void *data, size_t length, char *hash)
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)
etn_amount randEtnAmount(etn_amount upperlimit)
virtual bool mlsag_hash(const rct::keyV &long_message, rct::key &c)=0
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q)
void scalarmultBase(key &aG, const key &a)
void ge_p1p1_to_p3(ge_p3 *, const ge_p1p1 *)
void ge_add(ge_p1p1 *, const ge_p3 *, const ge_cached *)
rangeSig proveRange(key &C, key &mask, const etn_amount &amount)
const ge_p3 ge_p3_identity
void subKeys(key &AB, const key &A, const key &B)
void addKeys2(key &aGbB, const key &a, const key &b, const key &B)
void skpkGen(key &sk, key &pk)
bool verRctMG(const mgSig &mg, const ctkeyM &pubs, const ctkeyV &outPk, const key &txnFeeKey, const key &message)
bool verRctMGSimple(const key &message, const mgSig &mg, const ctkeyV &pubs, const key &C)
key scalarmult8(const key &P)
bool verRange(const key &C, const rangeSig &as)
int ge_frombytes_vartime(ge_p3 *, const unsigned char *)
void hash_to_scalar(const void *data, size_t length, ec_scalar &res)
void sc_sub(unsigned char *, const unsigned char *, const unsigned char *)
bool verRctNonSemanticsSimple(const rctSig &rv)
key hashToPoint(const key &hh)
RangeProofType range_proof_type
std::vector< ctkeyV > ctkeyM
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)
bool verifyBorromean(const boroSig &bb, const key64 P1, const key64 P2)
bool verBulletproof(const std::vector< const Bulletproof *> &proofs)
std::vector< Bulletproof > bulletproofs
void genC(key &C, const key &a, etn_amount amount)
bool verRctSemanticsSimple(const rctSig &rv)
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)
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)
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)
virtual bool ecdhDecode(rct::ecdhTuple &masked, const rct::key &sharedSec, bool short_amount)=0
size_t n_bulletproof_amounts(const Bulletproof &proof)