2#include <test/jtx/mpt.h>
4#include <test/jtx/Account.h>
5#include <test/jtx/Env.h>
6#include <test/jtx/amount.h>
7#include <test/jtx/credentials.h>
8#include <test/jtx/owners.h>
9#include <test/jtx/pay.h>
10#include <test/jtx/ter.h>
11#include <test/jtx/trust.h>
13#include <xrpl/basics/Slice.h>
14#include <xrpl/basics/StringUtilities.h>
15#include <xrpl/basics/base_uint.h>
16#include <xrpl/basics/contract.h>
17#include <xrpl/basics/strHex.h>
18#include <xrpl/beast/unit_test/suite.h>
19#include <xrpl/json/json_value.h>
20#include <xrpl/ledger/helpers/TokenHelpers.h>
21#include <xrpl/protocol/AccountID.h>
22#include <xrpl/protocol/Asset.h>
23#include <xrpl/protocol/ConfidentialTransfer.h>
24#include <xrpl/protocol/Indexes.h>
25#include <xrpl/protocol/LedgerFormats.h>
26#include <xrpl/protocol/Protocol.h>
27#include <xrpl/protocol/Rate.h>
28#include <xrpl/protocol/SField.h>
29#include <xrpl/protocol/TER.h>
30#include <xrpl/protocol/TxFlags.h>
31#include <xrpl/protocol/UintTypes.h>
32#include <xrpl/protocol/jss.h>
34#include <utility/mpt_utility.h>
36#include <mpt_protocol.h>
38#include <secp256k1_mpt.h>
57constexpr std::uint64_t kElGamalDecryptRangeLow = 0;
58constexpr std::uint64_t kElGamalDecryptRangeHigh = 3000;
70requireValue(std::optional<T>
const& opt,
char const* what)
83mpt_pedersen_proof_params
86 mpt_pedersen_proof_params res{};
88 res.pedersen_commitment, params.pedersenCommitment.data(), kMPT_PEDERSEN_COMMIT_SIZE);
89 res.amount = params.amt;
90 std::memcpy(res.ciphertext, params.encryptedAmt.data(), kMPT_ELGAMAL_TOTAL_SIZE);
91 std::memcpy(res.blinding_factor, params.blindingFactor.data(), kMPT_BLINDING_FACTOR_SIZE);
134 for (
auto const& h : holders)
136 if (accounts.
find(h.human()) != accounts.
cend())
138 accounts.
emplace(h.human(), h);
152 env_.fund(arg.xrp, issuer_);
153 for (auto const& it : holders_)
154 env_.fund(arg.xrpHolders, it.second);
157 env_.fund(arg.xrp, *arg.auditor);
163 env_.require(Owners(issuer_, 0));
164 for (auto const& it : holders_)
166 if (issuer_.id() == it.second.id())
167 Throw<std::runtime_error>(
"Issuer can't be holder");
168 env_.require(Owners(it.second, 0));
215 .auditor = arg.auditor,
237 jv[sfAccount] = arg.
issuer->human();
250 jv[sfTransactionType] = jss::MPTokenIssuanceCreate;
280 auto authAndPay = [&](
auto const& accts,
auto const&& getAcct) {
281 for (
auto const& it : accts)
286 if (arg.
pay && arg.
pay->first.empty())
291 for (
auto const& p : arg.
pay->first)
299 authAndPay(
holders_, [](
auto const& it) {
return it.second; });
303 authAndPay(*arg.
authorize, [](
auto const& it) { return it; });
308 if (arg.
pay->first.empty())
310 authAndPay(
holders_, [](
auto const& it) {
return it.second; });
314 authAndPay(arg.
pay->first, [](
auto const& it) { return it; });
326 jv[sfAccount] = arg.
issuer->human();
328 jv[sfTransactionType] = jss::MPTokenIssuanceDestroy;
358 jv[sfAccount] = arg.
account->human();
361 jv[sfHolder] = arg.
holder->human();
362 jv[sfTransactionType] = jss::MPTokenAuthorize;
432 for (
auto const&
holder : holders)
444 jv[sfAccount] = arg.
account->human();
449 [&jv]<
typename T>(T
const&
holder) {
452 jv[sfHolder] =
holder.human();
463 jv[sfDelegate] = arg.
delegate->human();
476 jv[sfTransactionType] = jss::MPTokenIssuanceSet;
507 if (*arg.
flags & tfMPTLock)
509 flags |= lsfMPTLocked;
511 else if (*arg.
flags & tfMPTUnlock)
513 flags &= ~lsfMPTLocked;
528 flags |= tfMPTCanHoldConfidentialBalance;
534 require(std::nullopt, arg.
holder.has_value());
536 require(*account,
false);
548 "MPTTester::set: issuer's pubkey is not set");
551 return strHex((*sle)[sfIssuerEncryptionKey]) ==
strHex(*issuerPubKey);
570 "MPTTester::set: auditor's pubkey is not set");
573 return strHex((*sle)[sfAuditorEncryptionKey]) ==
strHex(*auditorPubKey);
591 if (
auto const sle =
env_.le(key))
600 if (sle->isFieldPresent(sfDomainID))
601 return expected == sle->getFieldH256(sfDomainID);
610 [&](
SLEP const& sle) {
return expectedAmount == (*sle)[sfMPTAmount]; },
holder);
617 [&](
SLEP const& sle) {
return expectedAmount == (*sle)[sfOutstandingAmount]; });
624 return expectedAmount == (*sle)[~sfConfidentialOutstandingAmount].value_or(0);
638 if (sle->isFieldPresent(sfMPTokenMetadata))
639 return strHex(sle->getFieldVL(sfMPTokenMetadata)) ==
strHex(metadata);
648 [&](
SLEP const& sle) ->
bool {
return sle->isFieldPresent(sfMPTokenMetadata); });
655 if (sle->isFieldPresent(sfTransferFee))
656 return sle->getFieldU16(sfTransferFee) == transferFee;
664 return forObject([&](
SLEP const& sle) ->
bool {
return sle->isFieldPresent(sfTransferFee); });
749operator
Asset()
const
764 return sle->getFieldU64(sfOutstandingAmount);
769 return sle->getFieldU64(sfMPTAmount);
781 return (*sle)[~sfConfidentialOutstandingAmount].value_or(0);
791 uint256 const& contextHash)
const
799 if (!sleHolder || !sleIssuance)
802 auto const ciphertextBlob = sleHolder->getFieldVL(sfIssuerEncryptedBalance);
806 auto const pubKeyBlob = sleIssuance->getFieldVL(sfIssuerEncryptionKey);
812 if (mpt_get_clawback_proof(
817 ciphertextBlob.data(),
839 if (mpt_get_convert_proof(
840 requireValue(pubKey,
"pubKey").data(),
841 requireValue(privKey,
"privKey").data(),
854 Slice const& blindingFactor,
859 auto const pedersenBalanceParams = makePedersenParams(balanceParams);
864 auto const senderPrivKey =
getPrivKey(sender);
868 auto const senderPubKey =
getPubKey(sender);
877 for (
size_t i = 0; i < recipients.
size(); ++i)
879 auto const& r = recipients[i];
893 if (mpt_get_confidential_send_proof(
894 senderPrivKey->data(),
895 senderPubKey->data(),
899 blindingFactor.
data(),
902 &pedersenBalanceParams,
930 if (mpt_get_pedersen_commitment(amount, pedersenBlindingFactor.
data(), buf.
data()) != 0)
947 if (!sleMptoken || !sleMptoken->isFieldPresent(sfConfidentialBalanceSpending))
953 if (!holderPubKey || !holderPrivKey)
956 auto const pedersenParams = makePedersenParams(pcParams);
957 Buffer proof(kExpectedProofLength);
959 if (mpt_get_convert_back_proof(
960 holderPrivKey->data(),
961 holderPubKey->data(),
982 (*sle)[sfConfidentialBalanceInbox].data(),
983 (*sle)[sfConfidentialBalanceInbox].size());
988 (*sle)[sfConfidentialBalanceSpending].data(),
989 (*sle)[sfConfidentialBalanceSpending].size());
994 (*sle)[sfIssuerEncryptedBalance].data(), (*sle)[sfIssuerEncryptedBalance].size());
999 (*sle)[sfAuditorEncryptedBalance].data(), (*sle)[sfAuditorEncryptedBalance].size());
1011 [&](
SLEP const& sle) {
1012 flags = sle->getFlags();
1032template <
typename T>
1037 Buffer& holderCiphertext,
1038 Buffer& issuerCiphertext,
1040 Buffer& blindingFactor)
const
1045 if (arg.holderEncryptedAmt)
1047 holderCiphertext = *arg.holderEncryptedAmt;
1052 requireValue(arg.account,
"account"), requireValue(arg.amt,
"amt"), blindingFactor);
1055 jv[sfHolderEncryptedAmount.jsonName] =
strHex(holderCiphertext);
1058 if (arg.issuerEncryptedAmt)
1060 issuerCiphertext = *arg.issuerEncryptedAmt;
1067 jv[sfIssuerEncryptedAmount.jsonName] =
strHex(issuerCiphertext);
1070 if (arg.auditorEncryptedAmt)
1072 auditorCiphertext = *arg.auditorEncryptedAmt;
1074 else if (
auditor_.has_value() && arg.fillAuditorEncryptedAmt.value_or(
false))
1077 requireValue(
auditor_,
"auditor"), requireValue(arg.amt,
"amt"), blindingFactor);
1081 if (auditorCiphertext)
1082 jv[sfAuditorEncryptedAmount.jsonName] =
strHex(*auditorCiphertext);
1091 jv[sfAccount] = arg.
account->human();
1098 jv[jss::TransactionType] = jss::ConfidentialMPTConvert;
1121 arg, jv, holderCiphertext, issuerCiphertext, auditorCiphertext, blindingFactor);
1123 jv[sfBlindingFactor.jsonName] =
strHex(blindingFactor);
1126 jv[sfZKProof.jsonName] = *arg.
proof;
1135 auto const contextHash =
1141 jv[sfZKProof.jsonName] =
strHex(*proof);
1156 if (!prevInboxBalance || !prevSpendingBalance || !prevIssuerBalance)
1163 if (!prevAuditorBalance)
1174 *
this, requireValue(arg.
account,
"account"), holderAmt - requireValue(arg.
amt,
"amt")));
1176 return prevOutstanding && postOutstanding && *prevOutstanding == *postOutstanding;
1179 return prevConfidentialOutstanding + *arg.
amt == postConfidentialOutstanding;
1196 if (!postInboxBalance || !postIssuerBalance || !postSpendingBalance)
1201 auto const postAuditorBalance =
1204 if (!postAuditorBalance)
1213 [&]() ->
bool {
return *prevAuditorBalance + *arg.
amt == *postAuditorBalance; }));
1217 RequireAny([&]() ->
bool {
return *postSpendingBalance == *prevSpendingBalance; }));
1221 [&]() ->
bool {
return *prevIssuerBalance + *arg.
amt == *postIssuerBalance; }));
1225 [&]() ->
bool {
return *prevInboxBalance + *arg.
amt == *postInboxBalance; }));
1230 return *postInboxBalance + *postSpendingBalance == *postIssuerBalance;
1237 [&](
SLEP const& sle) ->
bool {
1244 "MPTTester::convert: holder's pubkey is "
1248 return strHex((*sle)[sfHolderEncryptionKey]) ==
strHex(*holderPubKey);
1264 jv[sfAccount] = arg.
account->human();
1271 jv[jss::TransactionType] = jss::ConfidentialMPTConvert;
1294 arg, jv, holderCiphertext, issuerCiphertext, auditorCiphertext, blindingFactor);
1296 jv[sfBlindingFactor.jsonName] =
strHex(blindingFactor);
1300 jv[sfZKProof.jsonName] = *arg.
proof;
1304 auto const contextHash =
1309 jv[sfZKProof.jsonName] =
strHex(*proof);
1324 jv[jss::TransactionType] = jss::ConfidentialMPTSend;
1328 jv[sfAccount] = arg.
account->human();
1337 jv[sfDestination] = arg.
dest->human();
1358 Buffer const blindingFactor =
1379 requireValue(
auditor_,
"auditor"), requireValue(arg.
amt,
"amt"), blindingFactor);
1382 jv[sfSenderEncryptedAmount] =
strHex(senderAmt);
1383 jv[sfDestinationEncryptedAmount] =
strHex(destAmt);
1384 jv[sfIssuerEncryptedAmount] =
strHex(issuerAmt);
1386 jv[sfAuditorEncryptedAmount] =
strHex(*auditorAmt);
1404 auto const prevSenderSpendingEncrypted =
1406 auto const prevSenderIssuerEncrypted =
1408 if (!prevSenderInbox || !prevSenderSpending || !prevSenderIssuer)
1412 auto const prevSenderAuditorEncrypted =
1417 if (!prevSenderAuditor)
1428 if (!prevDestInbox || !prevDestSpending || !prevDestIssuer)
1436 if (!prevDestAuditor)
1444 Buffer amountCommitment, balanceCommitment;
1454 jv[sfAmountCommitment] =
strHex(amountCommitment);
1466 jv[sfBalanceCommitment] =
strHex(balanceCommitment);
1471 jv[sfZKProof] = *arg.
proof;
1478 requireValue(arg.
account,
"account").id(),
1481 requireValue(arg.
dest,
"dest").id(),
1495 .publicKey =
Slice(*senderPubKey),
1496 .encryptedAmount = senderAmt,
1502 .publicKey =
Slice(*destPubKey),
1503 .encryptedAmount = destAmt,
1509 .publicKey =
Slice(*issuerPubKey),
1510 .encryptedAmount = issuerAmt,
1524 .publicKey =
Slice(*auditorPubKey),
1525 .encryptedAmount = *auditorAmt,
1536 if (arg.
account != arg.
dest && prevSenderSpendingEncrypted && *prevSenderSpending > 0)
1545 .pedersenCommitment = amountCommitment,
1547 .encryptedAmt = senderAmt,
1548 .blindingFactor = blindingFactor,
1551 .pedersenCommitment = balanceCommitment,
1552 .amt = *prevSenderSpending,
1553 .encryptedAmt = *prevSenderSpendingEncrypted,
1554 .blindingFactor = balanceBlindingFactor,
1560 jv[sfZKProof.jsonName] =
strHex(*proof);
1583 if (!postSenderInbox || !postSenderSpending || !postSenderIssuer)
1591 if (!postDestInbox || !postDestSpending || !postDestIssuer)
1599 env_.require(
RequireAny([&]() ->
bool {
return prevOA && postOA && *prevOA == *postOA; }));
1600 env_.require(
RequireAny([&]() ->
bool {
return prevCOA == postCOA; }));
1604 return *prevSenderSpending >= *arg.
amt &&
1605 *postSenderSpending == *prevSenderSpending - *arg.
amt;
1607 env_.require(
RequireAny([&]() ->
bool {
return postSenderInbox == prevSenderInbox; }));
1609 return *prevSenderIssuer >= *arg.
amt &&
1610 *postSenderIssuer == *prevSenderIssuer - *arg.
amt;
1615 RequireAny([&]() ->
bool {
return *postDestInbox == *prevDestInbox + *arg.
amt; }));
1616 env_.require(
RequireAny([&]() ->
bool {
return *postDestSpending == *prevDestSpending; }));
1618 RequireAny([&]() ->
bool {
return *postDestIssuer == *prevDestIssuer + *arg.
amt; }));
1622 [&]() ->
bool {
return *postSenderInbox + *postSenderSpending == *postSenderIssuer; }));
1624 [&]() ->
bool {
return *postDestInbox + *postDestSpending == *postDestIssuer; }));
1634 auto const postSenderAuditor =
1637 if (!postSenderAuditor || !postDestAuditor)
1641 return *postSenderAuditor == *postSenderIssuer &&
1642 *postDestAuditor == *postDestIssuer;
1647 return prevSenderAuditor >= *arg.
amt &&
1648 *postSenderAuditor == *prevSenderAuditor - *arg.
amt;
1653 [&]() ->
bool {
return *postDestAuditor == *prevDestAuditor + *arg.
amt; }));
1665 jv[jss::TransactionType] = jss::ConfidentialMPTSend;
1669 jv[sfAccount] = arg.
account->human();
1678 jv[sfDestination] = arg.
dest->human();
1699 Buffer const blindingFactor =
1719 requireValue(
auditor_,
"auditor"), requireValue(arg.
amt,
"amt"), blindingFactor);
1722 jv[sfSenderEncryptedAmount] =
strHex(senderAmt);
1723 jv[sfDestinationEncryptedAmount] =
strHex(destAmt);
1724 jv[sfIssuerEncryptedAmount] =
strHex(issuerAmt);
1726 jv[sfAuditorEncryptedAmount] =
strHex(*auditorAmt);
1740 prevSenderSpending = chain->spending;
1741 prevEncryptedSenderSpending = chain->encSpending;
1742 version = chain->version;
1747 if (!ledgerSpending)
1749 prevSenderSpending = *ledgerSpending;
1756 Buffer amountCommitment, balanceCommitment;
1766 jv[sfAmountCommitment] =
strHex(amountCommitment);
1778 jv[sfBalanceCommitment] =
strHex(balanceCommitment);
1782 jv[sfZKProof.jsonName] = *arg.
proof;
1787 requireValue(arg.
account,
"account").id(),
1790 requireValue(arg.
dest,
"dest").id(),
1802 .publicKey =
Slice(*senderPubKey),
1803 .encryptedAmount = senderAmt,
1809 .publicKey =
Slice(*destPubKey),
1810 .encryptedAmount = destAmt,
1816 .publicKey =
Slice(*issuerPubKey),
1817 .encryptedAmount = issuerAmt,
1830 .publicKey =
Slice(*auditorPubKey),
1831 .encryptedAmount = *auditorAmt,
1839 if (arg.
account != arg.
dest && prevEncryptedSenderSpending && prevSenderSpending > 0)
1848 .pedersenCommitment = amountCommitment,
1850 .encryptedAmt = senderAmt,
1851 .blindingFactor = blindingFactor,
1854 .pedersenCommitment = balanceCommitment,
1855 .amt = prevSenderSpending,
1856 .encryptedAmt = *prevEncryptedSenderSpending,
1857 .blindingFactor = balanceBlindingFactor,
1863 jv[sfZKProof.jsonName] =
strHex(*proof);
1877 auto const hexStr = jv[sfSenderEncryptedAmount.jsonName].
asString();
1878 auto const bytes =
strUnHex(hexStr);
1881 return Buffer(bytes->data(), bytes->size());
1891 if (!prevSpending || !prevEncSpending)
1896 *prevSpending,
Slice(*prevEncSpending), prevVersion, sendAmt,
Slice(senderEncAmt));
1899 return std::move(*chain);
1905 Slice const& currentEncSpending,
1908 Slice const& senderEncAmt)
1910 if (sendAmt > currentSpending)
1911 return std::nullopt;
1914 if (!newEncSpending)
1915 return std::nullopt;
1918 .spending = currentSpending - sendAmt,
1919 .encSpending = std::move(*newEncSpending),
1920 .version = currentVersion + 1,
1929 jv[sfAccount] = account.human();
1933 jv[sfHolder] = arg.
holder->human();
1940 jv[jss::TransactionType] = jss::ConfidentialMPTClawback;
1959 jv[sfZKProof] = *arg.
proof;
1972 requireValue(arg.
holder,
"holder"),
1973 requireValue(arg.
amt,
"amt"),
1974 requireValue(privKey,
"privKey"),
1979 jv[sfZKProof] =
strHex(*proof);
2003 [&]() ->
bool {
return prevCOA >= *arg.
amt && postCOA == prevCOA - *arg.
amt; }));
2005 return prevOA && postOA && *prevOA >= *arg.
amt && *postOA == *prevOA - *arg.
amt;
2022 env_.require(
RequireAny([&]() ->
bool {
return postVersion == prevVersion + 1; }));
2030 secp256k1_pubkey pubKey;
2031 if (secp256k1_elgamal_generate_keypair(
secp256k1Context(), privKey, &pubKey) == 0)
2037 if (secp256k1_ec_pubkey_serialize(
2038 secp256k1Context(), compressedPubKey, &outLen, &pubKey, SECP256K1_EC_COMPRESSED) != 1 ||
2054 return std::nullopt;
2063 return std::nullopt;
2070 if (
auto const pubKey =
getPubKey(account))
2085 return std::nullopt;
2089 return std::nullopt;
2093 return std::nullopt;
2095 uint64_t decryptedAmt = 0;
2096 if (secp256k1_elgamal_decrypt(
2102 kElGamalDecryptRangeLow,
2103 kElGamalDecryptRangeHigh) == 0)
2105 return std::nullopt;
2108 return decryptedAmt;
2130 return std::nullopt;
2143 jv[sfAccount] = arg.
account->human();
2159 jv[sfTransactionType] = jss::ConfidentialMPTMergeInbox;
2169 jv[sfAccount] = arg.
account->human();
2186 jv[sfTransactionType] = jss::ConfidentialMPTMergeInbox;
2197 if (!prevInboxBalance || !prevSpendingBalance || !prevIssuerBalance)
2209 auto const postAuditorEncrypted =
2213 if (!postInboxBalance || !postSpendingBalance || !postIssuerBalance ||
2214 !prevIssuerEncrypted || !postInboxEncrypted || !postIssuerEncrypted)
2218 env_.require(
RequireAny([&]() ->
bool {
return prevOA && postOA && *prevOA == *postOA; }));
2219 env_.require(
RequireAny([&]() ->
bool {
return prevCOA == postCOA; }));
2222 return *postSpendingBalance == *prevInboxBalance + *prevSpendingBalance &&
2223 *postInboxBalance == 0;
2227 RequireAny([&]() ->
bool {
return *prevIssuerBalance == *postIssuerBalance; }));
2234 requireValue(holderPubKey,
"holderPubKey"),
2235 requireValue(arg.
account,
"account").id(),
2240 env_.require(
RequireAny([&]() ->
bool {
return *postInboxEncrypted == *expectedInbox; }));
2242 RequireAny([&]() ->
bool {
return *postIssuerEncrypted == *prevIssuerEncrypted; }));
2244 return postAuditorEncrypted.has_value() == prevAuditorEncrypted.has_value() &&
2245 (!postAuditorEncrypted || *postAuditorEncrypted == *prevAuditorEncrypted);
2247 env_.require(
RequireAny([&]() ->
bool {
return postVersion == prevVersion + 1; }));
2250 return *postSpendingBalance + *postInboxBalance == *postIssuerBalance;
2259 return std::nullopt;
2264 return std::nullopt;
2266 return (*sle)[sfOutstandingAmount];
2282 return (*sle)[~sfConfidentialBalanceVersion].value_or(0);
2291 jv[sfAccount] = arg.
account->human();
2298 jv[jss::TransactionType] = jss::ConfidentialMPTConvertBack;
2319 arg, jv, holderCiphertext, issuerCiphertext, auditorCiphertext, blindingFactor);
2321 jv[sfBlindingFactor] =
strHex(blindingFactor);
2327 if (!prevInboxBalance || !prevSpendingBalance || !prevIssuerBalance)
2330 Buffer pedersenCommitment;
2341 jv[sfBalanceCommitment] =
strHex(pedersenCommitment);
2356 auto const prevEncryptedSpendingBalance =
2362 if (!prevEncryptedSpendingBalance)
2370 requireValue(arg.
amt,
"amt"),
2373 .pedersenCommitment = pedersenCommitment,
2374 .amt = *prevSpendingBalance,
2375 .encryptedAmt = *prevEncryptedSpendingBalance,
2376 .blindingFactor = pcBlindingFactor,
2379 jv[sfZKProof] =
strHex(proof);
2389 if (!prevAuditorBalance)
2402 *
this, requireValue(arg.
account,
"account"), holderAmt + requireValue(arg.
amt,
"amt")));
2404 return prevOutstanding && postOutstanding && *prevOutstanding == *postOutstanding;
2407 return prevConfidentialOutstanding - *arg.
amt == postConfidentialOutstanding;
2414 if (!postInboxBalance || !postIssuerBalance || !postSpendingBalance)
2419 auto const postAuditorBalance =
2422 if (!postAuditorBalance)
2427 [&]() ->
bool {
return *prevAuditorBalance - *arg.
amt == *postAuditorBalance; }));
2431 env_.require(
RequireAny([&]() ->
bool {
return *postInboxBalance == *prevInboxBalance; }));
2435 [&]() ->
bool {
return *prevIssuerBalance - *arg.
amt == *postIssuerBalance; }));
2439 [&]() ->
bool {
return *prevSpendingBalance - *arg.
amt == *postSpendingBalance; }));
2442 env_.require(
RequireAny([&]() ->
bool {
return postVersion == prevVersion + 1; }));
2447 return *postInboxBalance + *postSpendingBalance == *postIssuerBalance;
2458 jv[sfAccount] = arg.
account->human();
2465 jv[jss::TransactionType] = jss::ConfidentialMPTConvertBack;
2486 arg, jv, holderCiphertext, issuerCiphertext, auditorCiphertext, blindingFactor);
2488 jv[sfBlindingFactor] =
strHex(blindingFactor);
2491 if (!prevSpendingBalance)
2494 Buffer pedersenCommitment;
2505 jv[sfBalanceCommitment] =
strHex(pedersenCommitment);
2519 if (!prevEncSpending)
2527 requireValue(arg.
amt,
"amt"),
2530 .pedersenCommitment = pedersenCommitment,
2531 .amt = *prevSpendingBalance,
2532 .encryptedAmt = *prevEncSpending,
2533 .blindingFactor = pcBlindingFactor,
2537 jv[sfZKProof] =
strHex(proof);
bool expect(Condition const &shouldBeTrue)
Evaluate a test condition.
std::string asString() const
Returns the unquoted string value.
Like std::vector<char> but better.
std::size_t size() const noexcept
Returns the number of bytes in the buffer.
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
constexpr value_type value() const
Returns the underlying value.
An immutable linear range of bytes.
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
std::size_t size() const noexcept
Returns the number of bytes in the storage.
Immutable cryptographic account descriptor.
A transaction testing environment.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
beast::unit_test::Suite & test
void fillConversionCiphertexts(T const &arg, json::Value &jv, Buffer &holderCiphertext, Buffer &issuerCiphertext, std::optional< Buffer > &auditorCiphertext, Buffer &blindingFactor) const
static constexpr auto holderEncryptedInbox
std::optional< uint64_t > decryptAmount(Account const &account, Buffer const &amt) const
std::unordered_map< std::string, Account > const holders_
Buffer getConvertBackProof(Account const &holder, std::uint64_t const amount, uint256 const &contextHash, PedersenProofParams const &pcParams) const
void send(MPTConfidentialSend const &arg=MPTConfidentialSend{})
Buffer encryptAmount(Account const &account, uint64_t const amt, Buffer const &blindingFactor) const
bool forObject(std::function< bool(SLEP const &sle)> const &cb, std::optional< Account > const &holder=std::nullopt) const
void set(MPTSet const &set={})
bool checkMPTokenAmount(Account const &holder, std::int64_t expectedAmount) const
std::optional< MPTID > id_
json::Value convertJV(MPTConvert const &arg, std::uint32_t seq)
Build a confidential convert JV without submitting it.
static Buffer getPedersenCommitment(std::uint64_t const amount, Buffer const &pedersenBlindingFactor)
static json::Value destroyJV(MPTDestroy const &arg=MPTDestroy{})
std::optional< Buffer > getEncryptedBalance(Account const &account, EncryptedBalanceType option=holderEncryptedInbox) const
void convertBack(MPTConvertBack const &arg=MPTConvertBack{})
void pay(Account const &src, Account const &dest, std::int64_t amount, std::optional< TER > err=std::nullopt, std::optional< std::vector< std::string > > credentials=std::nullopt)
std::optional< uint64_t > getDecryptedBalance(Account const &account, EncryptedBalanceType balanceType) const
Account const & holder(std::string const &h) const
static json::Value authorizeJV(MPTAuthorize const &arg=MPTAuthorize{})
void create(MPTCreate const &arg=MPTCreate{})
bool isTransferFeePresent() const
std::optional< Buffer > getPrivKey(Account const &account) const
bool checkMetadata(std::string const &metadata) const
void confidentialClaw(MPTConfidentialClawback const &arg=MPTConfidentialClawback{})
bool checkFlags(uint32_t const expectedFlags, std::optional< Account > const &holder=std::nullopt) const
bool isMetadataPresent() const
MPT operator[](std::string const &name) const
static constexpr auto issuerEncryptedBalance
void authorizeHolders(Holders const &holders)
std::uint32_t getMPTokenVersion(Account const account) const
Account const & issuer() const
std::optional< std::int64_t > getIssuanceOutstandingBalance() const
static json::Value createJV(MPTCreate const &arg=MPTCreate{})
void authorize(MPTAuthorize const &arg=MPTAuthorize{})
std::optional< Buffer > getSchnorrProof(Account const &account, uint256 const &ctxHash) const
json::Value sendJV(MPTConfidentialSend const &arg, std::uint32_t seq, std::optional< ConfidentialSendChainState > chain=std::nullopt)
Build a confidential send JV.
ConfidentialSendChainState chainAfterSend(Account const &sender, std::uint64_t sendAmt, json::Value const &jv) const
Compute the projected sender state after a confidential send in a batch.
static json::Value setJV(MPTSet const &set={})
MPTID const & issuanceID() const
static constexpr auto holderEncryptedSpending
std::unordered_map< AccountID, Buffer > pubKeys_
std::unordered_map< AccountID, Buffer > privKeys_
std::optional< Buffer > getClawbackProof(Account const &holder, std::uint64_t amount, Buffer const &privateKey, uint256 const &txHash) const
std::int64_t getBalance(Account const &account) const
std::optional< Buffer > getConfidentialSendProof(Account const &sender, std::uint64_t const amount, std::vector< ConfidentialRecipient > const &recipients, Slice const &blindingFactor, uint256 const &contextHash, PedersenProofParams const &amountParams, PedersenProofParams const &balanceParams) const
std::optional< Account > const auditor_
json::Value mergeInboxJV(MPTMergeInbox const &arg=MPTMergeInbox{}) const
void claw(Account const &issuer, Account const &holder, std::int64_t amount, std::optional< TER > err=std::nullopt)
static constexpr auto auditorEncryptedBalance
MPTTester(Env &env, Account issuer, MPTInit const &constr={})
void generateKeyPair(Account const &account)
PrettyAmount mpt(std::int64_t amount) const
void destroy(MPTDestroy const &arg=MPTDestroy{})
std::int64_t getIssuanceConfidentialBalance() const
bool checkTransferFee(std::uint16_t transferFee) const
bool checkIssuanceConfidentialBalance(std::int64_t expectedAmount) const
bool checkDomainID(std::optional< uint256 > expected) const
void mergeInbox(MPTMergeInbox const &arg=MPTMergeInbox{})
PrettyAmount operator()(std::int64_t amount) const
void convert(MPTConvert const &arg=MPTConvert{})
std::uint32_t getFlags(std::optional< Account > const &holder) const
static std::unordered_map< std::string, Account > makeHolders(std::vector< Account > const &holders)
std::optional< Buffer > getPubKey(Account const &account) const
bool checkMPTokenOutstandingAmount(std::int64_t expectedAmount) const
TER submit(A const &arg, json::Value jv)
json::Value convertBackJV(MPTConvertBack const &arg, std::uint32_t seq)
Build a confidential convertBack JV without submitting it.
Converts to MPT Issue or STAmount.
Test helper that checks MPT issuance or holder balances.
MPTTester const & tester_
std::int64_t const amount_
void operator()(Env &env) const
Test helper that checks MPT flag settings after creation.
void operator()(Env &env) const
std::optional< Account > holder_
Match the number of items in the account's owner directory.
Test helper that accepts any condition supplied by a callback.
std::function< bool()> cb_
void operator()(Env &env) const
Set the expected result code for a JTx The test will fail if the code doesn't match.
@ Array
array value (ordered list)
Keylet mptokenIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
json::Value create(AccountID const &account, AccountID const &to, STAmount const &amount, NetClock::duration const &settleDelay, PublicKey const &pk, std::optional< NetClock::time_point > const &cancelAfter, std::optional< std::uint32_t > const &dstTag)
json::Value claw(Account const &account, STAmount const &amount, std::optional< Account > const &mptHolder)
json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
std::vector< STAmount > fund(jtx::Env &env, jtx::Account const &gw, std::vector< jtx::Account > const &accounts, std::vector< STAmount > const &amts, Fund how)
static MPTCreate makeMPTCreate(MPTInitDef const &arg)
static constexpr std::array< MPTSetFlagMapping, 6 > mptSetFlagMappings
Buffer gMakeZeroBuffer(std::size_t size)
Create a zero-initialized buffer for malformed cryptography test inputs.
std::vector< Account > Holders
std::optional< ConfidentialSendChainState > computeNextSendChainState(std::uint64_t currentSpending, Slice const ¤tEncSpending, std::uint32_t currentVersion, std::uint64_t sendAmt, Slice const &senderEncAmt)
Use this when building a second (or later) confidential send from the same account in the same batch.
static Buffer parseSenderEncAmt(json::Value const &jv)
constexpr std::size_t kEcPubKeyLength
Length of EC public key (compressed).
constexpr std::uint8_t kEcCompressedPrefixEvenY
Compressed EC point prefix for even y-coordinate.
constexpr FlagValue tmfMPTSetCanLock
constexpr FlagValue tmfMPTSetCanClawback
constexpr std::size_t kEcBlindingFactorLength
Length of the EC blinding factor in bytes.
std::optional< Buffer > encryptCanonicalZeroAmount(Slice const &pubKeySlice, AccountID const &account, MPTID const &mptId)
Generates the canonical zero encryption for a specific MPToken.
std::string strHex(FwdIt begin, FwdIt end)
constexpr FlagValue tmfMPTSetCanHoldConfidentialBalance
constexpr std::size_t kEcClawbackProofLength
Length of the ZKProof for ConfidentialMPTClawback.
std::optional< Buffer > encryptAmount(uint64_t const amt, Slice const &pubKeySlice, Slice const &blindingFactor)
Encrypts an amount using ElGamal encryption.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
constexpr std::size_t kEcSchnorrProofLength
Length of Schnorr ZKProof for public key registration (compact form) in bytes.
constexpr FlagValue tmfMPTSetCanTrade
std::optional< EcPair > makeEcPair(Slice const &buffer)
Parses an ElGamal ciphertext into two secp256k1 public key components.
constexpr std::size_t kEcGamalEncryptedTotalLength
EC ElGamal ciphertext length: two compressed EC points concatenated.
std::string to_string(BaseUInt< Bits, Tag > const &a)
constexpr std::size_t kEcConvertBackProofLength
128 bytes compact sigma proof + 688 bytes single bulletproof.
uint256 getConvertBackContextHash(AccountID const &account, uint192 const &issuanceID, std::uint32_t sequence, std::uint32_t version)
Generates the context hash for ConfidentialMPTConvertBack transactions.
constexpr FlagValue tmfMPTSetCanTransfer
constexpr FlagValue tmfMPTSetCanEscrow
constexpr std::size_t kEcPedersenCommitmentLength
Length of Pedersen Commitment (compressed).
std::optional< Buffer > homomorphicSubtract(Slice const &a, Slice const &b)
Homomorphically subtracts two ElGamal ciphertexts.
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
BaseUInt< 192 > MPTID
MPTID is a 192-bit value representing MPT Issuance ID, which is a concatenation of a 32-bit sequence ...
uint256 getConvertContextHash(AccountID const &account, uint192 const &issuanceID, std::uint32_t sequence)
Generates the context hash for ConfidentialMPTConvert transactions.
secp256k1_context const * secp256k1Context()
uint256 getClawbackContextHash(AccountID const &account, uint192 const &issuanceID, std::uint32_t sequence, AccountID const &holder)
Generates the context hash for ConfidentialMPTClawback transactions.
Buffer generateBlindingFactor()
Generates a cryptographically secure blinding factor (size=xrpl::kEcBlindingFactorLength).
uint256 getSendContextHash(AccountID const &account, uint192 const &issuanceID, std::uint32_t sequence, AccountID const &destination, std::uint32_t version)
Generates the context hash for ConfidentialMPTSend transactions.
constexpr std::size_t kEcSendProofLength
192 bytes compact sigma proof + 754 bytes double bulletproof.
bool isTesSuccess(TER x) noexcept
STAmount multiply(STAmount const &amount, Number const &frac, Number::RoundingMode rm)
constexpr std::size_t kEcPrivKeyLength
Length of EC private key in bytes.
MPTID makeMptID(std::uint32_t sequence, AccountID const &account)
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
constexpr FlagValue tmfMPTSetRequireAuth
When building multiple confidential sends from the same account inside a single batch transaction,...
Arguments for building an MPTokenAuthorize test transaction.
std::optional< Account > holder
std::optional< Account > account
std::optional< MPTID > id
std::optional< std::uint32_t > flags
Arguments for building a ConfidentialMPTClawback test transaction.
std::optional< std::uint32_t > ticketSeq
std::optional< std::string > proof
std::optional< std::uint64_t > amt
std::optional< MPTID > id
std::optional< Account > account
std::optional< Account > holder
Arguments for building a ConfidentialMPTSend test transaction.
std::optional< std::vector< std::string > > credentials
std::optional< Buffer > balanceCommitment
std::optional< MPTID > id
std::optional< std::uint32_t > ticketSeq
std::optional< std::uint64_t > amt
std::optional< bool > fillAuditorEncryptedAmt
std::optional< Account > account
std::optional< Buffer > auditorEncryptedAmt
std::optional< Account > dest
std::optional< Buffer > blindingFactor
std::optional< Buffer > amountCommitment
std::optional< std::string > proof
std::optional< Buffer > senderEncryptedAmt
std::optional< Buffer > destEncryptedAmt
std::optional< Buffer > issuerEncryptedAmt
Arguments for building a ConfidentialMPTConvertBack test transaction.
std::optional< Buffer > auditorEncryptedAmt
std::optional< MPTID > id
std::optional< std::uint64_t > amt
std::optional< Account > account
std::optional< std::uint32_t > ticketSeq
std::optional< Buffer > proof
std::optional< Buffer > pedersenCommitment
Arguments for building a ConfidentialMPTConvert test transaction.
std::optional< MPTID > id
std::optional< std::uint64_t > amt
std::optional< Buffer > auditorEncryptedAmt
std::optional< bool > fillSchnorrProof
std::optional< Buffer > holderPubKey
std::optional< Account > account
std::optional< std::string > proof
std::optional< std::uint32_t > ticketSeq
Arguments for building an MPTokenIssuanceCreate test transaction.
std::optional< std::uint8_t > assetScale
std::optional< std::uint32_t > mutableFlags
std::optional< std::string > metadata
std::optional< std::uint32_t > flags
std::optional< uint256 > domainID
std::optional< std::uint64_t > maxAmt
std::optional< Account > issuer
std::optional< std::pair< std::vector< Account >, std::uint64_t > > pay
std::optional< std::uint16_t > transferFee
std::optional< std::vector< Account > > authorize
Arguments for building an MPTokenIssuanceDestroy test transaction.
std::optional< Account > issuer
std::optional< MPTID > id
Full constructor arguments for MPTTester initialization.
std::optional< std::uint32_t > mutableFlags
std::uint16_t transferFee
std::optional< std::uint64_t > maxAmt
std::optional< std::uint64_t > pay
Arguments for initializing funded MPT test accounts and issuance.
std::optional< Account > auditor
Arguments for building a ConfidentialMPTMergeInbox test transaction.
std::optional< MPTID > id
std::optional< Account > account
Arguments for building an MPTokenIssuanceSet test transaction.
std::optional< uint256 > domainID
std::optional< Account > account
std::optional< Buffer > auditorPubKey
std::optional< MPTID > id
std::optional< std::uint16_t > transferFee
std::optional< std::uint32_t > flags
std::optional< std::variant< Account, AccountID > > holder
std::optional< std::uint32_t > mutableFlags
std::optional< std::string > metadata
std::optional< Buffer > issuerPubKey
std::optional< Account > delegate
Stores the parameters that are exclusively used to generate a Pedersen linkage proof.
Buffer const pedersenCommitment
The Pedersen commitment used by the proof.
Represents an XRP, IOU, or MPT quantity This customizes the string conversion and supports XRP conver...