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>
33#include <xrpl/tx/transactors/token/MPTokenIssuanceSet.h>
35#include <utility/mpt_utility.h>
37#include <mpt_protocol.h>
39#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);
119 for (
auto const& h : holders)
121 if (accounts.
find(h.human()) != accounts.
cend())
123 accounts.
emplace(h.human(), h);
137 env_.fund(arg.xrp, issuer_);
138 for (auto const& it : holders_)
139 env_.fund(arg.xrpHolders, it.second);
142 env_.fund(arg.xrp, *arg.auditor);
148 env_.require(Owners(issuer_, 0));
149 for (auto const& it : holders_)
151 if (issuer_.id() == it.second.id())
152 Throw<std::runtime_error>(
"Issuer can't be holder");
153 env_.require(Owners(it.second, 0));
200 .auditor = arg.auditor,
222 jv[sfAccount] = arg.
issuer->human();
235 jv[sfTransactionType] = jss::MPTokenIssuanceCreate;
265 auto authAndPay = [&](
auto const& accts,
auto const&& getAcct) {
266 for (
auto const& it : accts)
271 if (arg.
pay && arg.
pay->first.empty())
276 for (
auto const& p : arg.
pay->first)
284 authAndPay(
holders_, [](
auto const& it) {
return it.second; });
288 authAndPay(*arg.
authorize, [](
auto const& it) { return it; });
293 if (arg.
pay->first.empty())
295 authAndPay(
holders_, [](
auto const& it) {
return it.second; });
299 authAndPay(arg.
pay->first, [](
auto const& it) { return it; });
311 jv[sfAccount] = arg.
issuer->human();
313 jv[sfTransactionType] = jss::MPTokenIssuanceDestroy;
343 jv[sfAccount] = arg.
account->human();
346 jv[sfHolder] = arg.
holder->human();
347 jv[sfTransactionType] = jss::MPTokenAuthorize;
417 for (
auto const&
holder : holders)
429 jv[sfAccount] = arg.
account->human();
434 [&jv]<
typename T>(T
const&
holder) {
437 jv[sfHolder] =
holder.human();
448 jv[sfDelegate] = arg.
delegate->human();
461 jv[sfTransactionType] = jss::MPTokenIssuanceSet;
490 if (*arg.
flags & tfMPTLock)
492 flags |= lsfMPTLocked;
494 else if (*arg.
flags & tfMPTUnlock)
496 flags &= ~lsfMPTLocked;
501 if ((*arg.
flags & f.setFlag) != 0u)
503 flags |= f.ledgerFlag;
511 require(std::nullopt, arg.
holder.has_value());
513 require(*account,
false);
527 return strHex((*sle)[sfIssuerEncryptionKey]) ==
strHex(*issuerPubKey);
546 "MPTTester::set: auditor's pubkey is not set");
549 return strHex((*sle)[sfAuditorEncryptionKey]) ==
strHex(*auditorPubKey);
566 if (
auto const sle =
env_.le(key))
575 if (sle->isFieldPresent(sfDomainID))
576 return expected == sle->getFieldH256(sfDomainID);
585 [&](
SLEP const& sle) {
return expectedAmount == (*sle)[sfMPTAmount]; },
holder);
592 [&](
SLEP const& sle) {
return expectedAmount == (*sle)[sfOutstandingAmount]; });
599 return expectedAmount == (*sle)[~sfConfidentialOutstandingAmount].value_or(0);
613 if (sle->isFieldPresent(sfMPTokenMetadata))
614 return strHex(sle->getFieldVL(sfMPTokenMetadata)) ==
strHex(metadata);
623 [&](
SLEP const& sle) ->
bool {
return sle->isFieldPresent(sfMPTokenMetadata); });
630 if (sle->isFieldPresent(sfTransferFee))
631 return sle->getFieldU16(sfTransferFee) == transferFee;
639 return forObject([&](
SLEP const& sle) ->
bool {
return sle->isFieldPresent(sfTransferFee); });
647 return sle->getFieldU32(sfImmutableFlags) == expectedFlags;
733operator
Asset()
const
748 return sle->getFieldU64(sfOutstandingAmount);
753 return sle->getFieldU64(sfMPTAmount);
765 return (*sle)[~sfConfidentialOutstandingAmount].value_or(0);
775 uint256 const& contextHash)
const
783 if (!sleHolder || !sleIssuance)
786 auto const ciphertextBlob = sleHolder->getFieldVL(sfIssuerEncryptedBalance);
790 auto const pubKeyBlob = sleIssuance->getFieldVL(sfIssuerEncryptionKey);
796 if (mpt_get_clawback_proof(
801 ciphertextBlob.data(),
823 if (mpt_get_convert_proof(
824 requireValue(pubKey,
"pubKey").data(),
825 requireValue(privKey,
"privKey").data(),
838 Slice const& blindingFactor,
843 auto const pedersenBalanceParams = makePedersenParams(balanceParams);
848 auto const senderPrivKey =
getPrivKey(sender);
852 auto const senderPubKey =
getPubKey(sender);
861 for (
size_t i = 0; i < recipients.
size(); ++i)
863 auto const& r = recipients[i];
877 if (mpt_get_confidential_send_proof(
878 senderPrivKey->data(),
879 senderPubKey->data(),
883 blindingFactor.
data(),
886 &pedersenBalanceParams,
914 if (mpt_get_pedersen_commitment(amount, pedersenBlindingFactor.
data(), buf.
data()) != 0)
931 if (!sleMptoken || !sleMptoken->isFieldPresent(sfConfidentialBalanceSpending))
937 if (!holderPubKey || !holderPrivKey)
940 auto const pedersenParams = makePedersenParams(pcParams);
941 Buffer proof(kExpectedProofLength);
943 if (mpt_get_convert_back_proof(
944 holderPrivKey->data(),
945 holderPubKey->data(),
966 (*sle)[sfConfidentialBalanceInbox].data(),
967 (*sle)[sfConfidentialBalanceInbox].size());
972 (*sle)[sfConfidentialBalanceSpending].data(),
973 (*sle)[sfConfidentialBalanceSpending].size());
978 (*sle)[sfIssuerEncryptedBalance].data(), (*sle)[sfIssuerEncryptedBalance].size());
983 (*sle)[sfAuditorEncryptedBalance].data(), (*sle)[sfAuditorEncryptedBalance].size());
995 [&](
SLEP const& sle) {
996 flags = sle->getFlags();
1016template <
typename T>
1021 Buffer& holderCiphertext,
1022 Buffer& issuerCiphertext,
1024 Buffer& blindingFactor)
const
1029 if (arg.holderEncryptedAmt)
1031 holderCiphertext = *arg.holderEncryptedAmt;
1036 requireValue(arg.account,
"account"), requireValue(arg.amt,
"amt"), blindingFactor);
1039 jv[sfHolderEncryptedAmount.jsonName] =
strHex(holderCiphertext);
1042 if (arg.issuerEncryptedAmt)
1044 issuerCiphertext = *arg.issuerEncryptedAmt;
1051 jv[sfIssuerEncryptedAmount.jsonName] =
strHex(issuerCiphertext);
1054 if (arg.auditorEncryptedAmt)
1056 auditorCiphertext = *arg.auditorEncryptedAmt;
1058 else if (
auditor_.has_value() && arg.fillAuditorEncryptedAmt.value_or(
false))
1061 requireValue(
auditor_,
"auditor"), requireValue(arg.amt,
"amt"), blindingFactor);
1065 if (auditorCiphertext)
1066 jv[sfAuditorEncryptedAmount.jsonName] =
strHex(*auditorCiphertext);
1075 jv[sfAccount] = arg.
account->human();
1082 jv[jss::TransactionType] = jss::ConfidentialMPTConvert;
1105 arg, jv, holderCiphertext, issuerCiphertext, auditorCiphertext, blindingFactor);
1107 jv[sfBlindingFactor.jsonName] =
strHex(blindingFactor);
1110 jv[sfZKProof.jsonName] = *arg.
proof;
1119 auto const contextHash =
1125 jv[sfZKProof.jsonName] =
strHex(*proof);
1140 if (!prevInboxBalance || !prevSpendingBalance || !prevIssuerBalance)
1147 if (!prevAuditorBalance)
1158 *
this, requireValue(arg.
account,
"account"), holderAmt - requireValue(arg.
amt,
"amt")));
1160 return prevOutstanding && postOutstanding && *prevOutstanding == *postOutstanding;
1163 return prevConfidentialOutstanding + *arg.
amt == postConfidentialOutstanding;
1180 if (!postInboxBalance || !postIssuerBalance || !postSpendingBalance)
1185 auto const postAuditorBalance =
1188 if (!postAuditorBalance)
1197 [&]() ->
bool {
return *prevAuditorBalance + *arg.
amt == *postAuditorBalance; }));
1201 RequireAny([&]() ->
bool {
return *postSpendingBalance == *prevSpendingBalance; }));
1205 [&]() ->
bool {
return *prevIssuerBalance + *arg.
amt == *postIssuerBalance; }));
1209 [&]() ->
bool {
return *prevInboxBalance + *arg.
amt == *postInboxBalance; }));
1214 return *postInboxBalance + *postSpendingBalance == *postIssuerBalance;
1221 [&](
SLEP const& sle) ->
bool {
1228 "MPTTester::convert: holder's pubkey is "
1232 return strHex((*sle)[sfHolderEncryptionKey]) ==
strHex(*holderPubKey);
1248 jv[sfAccount] = arg.
account->human();
1255 jv[jss::TransactionType] = jss::ConfidentialMPTConvert;
1278 arg, jv, holderCiphertext, issuerCiphertext, auditorCiphertext, blindingFactor);
1280 jv[sfBlindingFactor.jsonName] =
strHex(blindingFactor);
1284 jv[sfZKProof.jsonName] = *arg.
proof;
1288 auto const contextHash =
1293 jv[sfZKProof.jsonName] =
strHex(*proof);
1308 jv[jss::TransactionType] = jss::ConfidentialMPTSend;
1312 jv[sfAccount] = arg.
account->human();
1321 jv[sfDestination] = arg.
dest->human();
1342 Buffer const blindingFactor =
1363 requireValue(
auditor_,
"auditor"), requireValue(arg.
amt,
"amt"), blindingFactor);
1366 jv[sfSenderEncryptedAmount] =
strHex(senderAmt);
1367 jv[sfDestinationEncryptedAmount] =
strHex(destAmt);
1368 jv[sfIssuerEncryptedAmount] =
strHex(issuerAmt);
1370 jv[sfAuditorEncryptedAmount] =
strHex(*auditorAmt);
1388 auto const prevSenderSpendingEncrypted =
1390 auto const prevSenderIssuerEncrypted =
1392 if (!prevSenderInbox || !prevSenderSpending || !prevSenderIssuer)
1396 auto const prevSenderAuditorEncrypted =
1401 if (!prevSenderAuditor)
1412 if (!prevDestInbox || !prevDestSpending || !prevDestIssuer)
1420 if (!prevDestAuditor)
1428 Buffer amountCommitment, balanceCommitment;
1438 jv[sfAmountCommitment] =
strHex(amountCommitment);
1450 jv[sfBalanceCommitment] =
strHex(balanceCommitment);
1455 jv[sfZKProof] = *arg.
proof;
1462 requireValue(arg.
account,
"account").id(),
1465 requireValue(arg.
dest,
"dest").id(),
1479 .publicKey =
Slice(*senderPubKey),
1480 .encryptedAmount = senderAmt,
1486 .publicKey =
Slice(*destPubKey),
1487 .encryptedAmount = destAmt,
1493 .publicKey =
Slice(*issuerPubKey),
1494 .encryptedAmount = issuerAmt,
1508 .publicKey =
Slice(*auditorPubKey),
1509 .encryptedAmount = *auditorAmt,
1520 if (arg.
account != arg.
dest && prevSenderSpendingEncrypted && *prevSenderSpending > 0)
1529 .pedersenCommitment = amountCommitment,
1531 .encryptedAmt = senderAmt,
1532 .blindingFactor = blindingFactor,
1535 .pedersenCommitment = balanceCommitment,
1536 .amt = *prevSenderSpending,
1537 .encryptedAmt = *prevSenderSpendingEncrypted,
1538 .blindingFactor = balanceBlindingFactor,
1544 jv[sfZKProof.jsonName] =
strHex(*proof);
1567 if (!postSenderInbox || !postSenderSpending || !postSenderIssuer)
1575 if (!postDestInbox || !postDestSpending || !postDestIssuer)
1583 env_.require(
RequireAny([&]() ->
bool {
return prevOA && postOA && *prevOA == *postOA; }));
1584 env_.require(
RequireAny([&]() ->
bool {
return prevCOA == postCOA; }));
1588 return *prevSenderSpending >= *arg.
amt &&
1589 *postSenderSpending == *prevSenderSpending - *arg.
amt;
1591 env_.require(
RequireAny([&]() ->
bool {
return postSenderInbox == prevSenderInbox; }));
1593 return *prevSenderIssuer >= *arg.
amt &&
1594 *postSenderIssuer == *prevSenderIssuer - *arg.
amt;
1599 RequireAny([&]() ->
bool {
return *postDestInbox == *prevDestInbox + *arg.
amt; }));
1600 env_.require(
RequireAny([&]() ->
bool {
return *postDestSpending == *prevDestSpending; }));
1602 RequireAny([&]() ->
bool {
return *postDestIssuer == *prevDestIssuer + *arg.
amt; }));
1606 [&]() ->
bool {
return *postSenderInbox + *postSenderSpending == *postSenderIssuer; }));
1608 [&]() ->
bool {
return *postDestInbox + *postDestSpending == *postDestIssuer; }));
1618 auto const postSenderAuditor =
1621 if (!postSenderAuditor || !postDestAuditor)
1625 return *postSenderAuditor == *postSenderIssuer &&
1626 *postDestAuditor == *postDestIssuer;
1631 return prevSenderAuditor >= *arg.
amt &&
1632 *postSenderAuditor == *prevSenderAuditor - *arg.
amt;
1637 [&]() ->
bool {
return *postDestAuditor == *prevDestAuditor + *arg.
amt; }));
1649 jv[jss::TransactionType] = jss::ConfidentialMPTSend;
1653 jv[sfAccount] = arg.
account->human();
1662 jv[sfDestination] = arg.
dest->human();
1683 Buffer const blindingFactor =
1703 requireValue(
auditor_,
"auditor"), requireValue(arg.
amt,
"amt"), blindingFactor);
1706 jv[sfSenderEncryptedAmount] =
strHex(senderAmt);
1707 jv[sfDestinationEncryptedAmount] =
strHex(destAmt);
1708 jv[sfIssuerEncryptedAmount] =
strHex(issuerAmt);
1710 jv[sfAuditorEncryptedAmount] =
strHex(*auditorAmt);
1724 prevSenderSpending = chain->spending;
1725 prevEncryptedSenderSpending = chain->encSpending;
1726 version = chain->version;
1731 if (!ledgerSpending)
1733 prevSenderSpending = *ledgerSpending;
1740 Buffer amountCommitment, balanceCommitment;
1750 jv[sfAmountCommitment] =
strHex(amountCommitment);
1762 jv[sfBalanceCommitment] =
strHex(balanceCommitment);
1766 jv[sfZKProof.jsonName] = *arg.
proof;
1771 requireValue(arg.
account,
"account").id(),
1774 requireValue(arg.
dest,
"dest").id(),
1786 .publicKey =
Slice(*senderPubKey),
1787 .encryptedAmount = senderAmt,
1793 .publicKey =
Slice(*destPubKey),
1794 .encryptedAmount = destAmt,
1800 .publicKey =
Slice(*issuerPubKey),
1801 .encryptedAmount = issuerAmt,
1814 .publicKey =
Slice(*auditorPubKey),
1815 .encryptedAmount = *auditorAmt,
1823 if (arg.
account != arg.
dest && prevEncryptedSenderSpending && prevSenderSpending > 0)
1832 .pedersenCommitment = amountCommitment,
1834 .encryptedAmt = senderAmt,
1835 .blindingFactor = blindingFactor,
1838 .pedersenCommitment = balanceCommitment,
1839 .amt = prevSenderSpending,
1840 .encryptedAmt = *prevEncryptedSenderSpending,
1841 .blindingFactor = balanceBlindingFactor,
1847 jv[sfZKProof.jsonName] =
strHex(*proof);
1861 auto const hexStr = jv[sfSenderEncryptedAmount.jsonName].
asString();
1862 auto const bytes =
strUnHex(hexStr);
1865 return Buffer(bytes->data(), bytes->size());
1875 if (!prevSpending || !prevEncSpending)
1880 *prevSpending,
Slice(*prevEncSpending), prevVersion, sendAmt,
Slice(senderEncAmt));
1883 return std::move(*chain);
1889 Slice const& currentEncSpending,
1892 Slice const& senderEncAmt)
1894 if (sendAmt > currentSpending)
1895 return std::nullopt;
1898 if (!newEncSpending)
1899 return std::nullopt;
1902 .spending = currentSpending - sendAmt,
1903 .encSpending = std::move(*newEncSpending),
1904 .version = currentVersion + 1,
1913 jv[sfAccount] = account.human();
1917 jv[sfHolder] = arg.
holder->human();
1924 jv[jss::TransactionType] = jss::ConfidentialMPTClawback;
1943 jv[sfZKProof] = *arg.
proof;
1956 requireValue(arg.
holder,
"holder"),
1957 requireValue(arg.
amt,
"amt"),
1958 requireValue(privKey,
"privKey"),
1963 jv[sfZKProof] =
strHex(*proof);
1987 [&]() ->
bool {
return prevCOA >= *arg.
amt && postCOA == prevCOA - *arg.
amt; }));
1989 return prevOA && postOA && *prevOA >= *arg.
amt && *postOA == *prevOA - *arg.
amt;
2006 env_.require(
RequireAny([&]() ->
bool {
return postVersion == prevVersion + 1; }));
2014 secp256k1_pubkey pubKey;
2015 if (secp256k1_elgamal_generate_keypair(
secp256k1Context(), privKey, &pubKey) == 0)
2021 if (secp256k1_ec_pubkey_serialize(
2022 secp256k1Context(), compressedPubKey, &outLen, &pubKey, SECP256K1_EC_COMPRESSED) != 1 ||
2038 return std::nullopt;
2047 return std::nullopt;
2054 if (
auto const pubKey =
getPubKey(account))
2069 return std::nullopt;
2073 return std::nullopt;
2077 return std::nullopt;
2079 uint64_t decryptedAmt = 0;
2080 if (secp256k1_elgamal_decrypt(
2086 kElGamalDecryptRangeLow,
2087 kElGamalDecryptRangeHigh) == 0)
2089 return std::nullopt;
2092 return decryptedAmt;
2114 return std::nullopt;
2127 jv[sfAccount] = arg.
account->human();
2143 jv[sfTransactionType] = jss::ConfidentialMPTMergeInbox;
2153 jv[sfAccount] = arg.
account->human();
2170 jv[sfTransactionType] = jss::ConfidentialMPTMergeInbox;
2181 if (!prevInboxBalance || !prevSpendingBalance || !prevIssuerBalance)
2193 auto const postAuditorEncrypted =
2197 if (!postInboxBalance || !postSpendingBalance || !postIssuerBalance ||
2198 !prevIssuerEncrypted || !postInboxEncrypted || !postIssuerEncrypted)
2202 env_.require(
RequireAny([&]() ->
bool {
return prevOA && postOA && *prevOA == *postOA; }));
2203 env_.require(
RequireAny([&]() ->
bool {
return prevCOA == postCOA; }));
2206 return *postSpendingBalance == *prevInboxBalance + *prevSpendingBalance &&
2207 *postInboxBalance == 0;
2211 RequireAny([&]() ->
bool {
return *prevIssuerBalance == *postIssuerBalance; }));
2218 requireValue(holderPubKey,
"holderPubKey"),
2219 requireValue(arg.
account,
"account").id(),
2224 env_.require(
RequireAny([&]() ->
bool {
return *postInboxEncrypted == *expectedInbox; }));
2226 RequireAny([&]() ->
bool {
return *postIssuerEncrypted == *prevIssuerEncrypted; }));
2228 return postAuditorEncrypted.has_value() == prevAuditorEncrypted.has_value() &&
2229 (!postAuditorEncrypted || *postAuditorEncrypted == *prevAuditorEncrypted);
2231 env_.require(
RequireAny([&]() ->
bool {
return postVersion == prevVersion + 1; }));
2234 return *postSpendingBalance + *postInboxBalance == *postIssuerBalance;
2243 return std::nullopt;
2248 return std::nullopt;
2250 return (*sle)[sfOutstandingAmount];
2266 return (*sle)[~sfConfidentialBalanceVersion].value_or(0);
2275 jv[sfAccount] = arg.
account->human();
2282 jv[jss::TransactionType] = jss::ConfidentialMPTConvertBack;
2303 arg, jv, holderCiphertext, issuerCiphertext, auditorCiphertext, blindingFactor);
2305 jv[sfBlindingFactor] =
strHex(blindingFactor);
2311 if (!prevInboxBalance || !prevSpendingBalance || !prevIssuerBalance)
2314 Buffer pedersenCommitment;
2325 jv[sfBalanceCommitment] =
strHex(pedersenCommitment);
2340 auto const prevEncryptedSpendingBalance =
2346 if (!prevEncryptedSpendingBalance)
2354 requireValue(arg.
amt,
"amt"),
2357 .pedersenCommitment = pedersenCommitment,
2358 .amt = *prevSpendingBalance,
2359 .encryptedAmt = *prevEncryptedSpendingBalance,
2360 .blindingFactor = pcBlindingFactor,
2363 jv[sfZKProof] =
strHex(proof);
2373 if (!prevAuditorBalance)
2386 *
this, requireValue(arg.
account,
"account"), holderAmt + requireValue(arg.
amt,
"amt")));
2388 return prevOutstanding && postOutstanding && *prevOutstanding == *postOutstanding;
2391 return prevConfidentialOutstanding - *arg.
amt == postConfidentialOutstanding;
2398 if (!postInboxBalance || !postIssuerBalance || !postSpendingBalance)
2403 auto const postAuditorBalance =
2406 if (!postAuditorBalance)
2411 [&]() ->
bool {
return *prevAuditorBalance - *arg.
amt == *postAuditorBalance; }));
2415 env_.require(
RequireAny([&]() ->
bool {
return *postInboxBalance == *prevInboxBalance; }));
2419 [&]() ->
bool {
return *prevIssuerBalance - *arg.
amt == *postIssuerBalance; }));
2423 [&]() ->
bool {
return *prevSpendingBalance - *arg.
amt == *postSpendingBalance; }));
2426 env_.require(
RequireAny([&]() ->
bool {
return postVersion == prevVersion + 1; }));
2431 return *postInboxBalance + *postSpendingBalance == *postIssuerBalance;
2442 jv[sfAccount] = arg.
account->human();
2449 jv[jss::TransactionType] = jss::ConfidentialMPTConvertBack;
2470 arg, jv, holderCiphertext, issuerCiphertext, auditorCiphertext, blindingFactor);
2472 jv[sfBlindingFactor] =
strHex(blindingFactor);
2475 if (!prevSpendingBalance)
2478 Buffer pedersenCommitment;
2489 jv[sfBalanceCommitment] =
strHex(pedersenCommitment);
2503 if (!prevEncSpending)
2511 requireValue(arg.
amt,
"amt"),
2514 .pedersenCommitment = pedersenCommitment,
2515 .amt = *prevSpendingBalance,
2516 .encryptedAmt = *prevEncSpending,
2517 .blindingFactor = pcBlindingFactor,
2521 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.
static constexpr std::array< FlagMapping, 7 > flagMapping
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_
bool checkImmutableFlags(std::uint32_t expectedFlags) const
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 mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Keylet mptokenIssuance(MPTID const &issuanceID) 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)
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 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 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.
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 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).
MPTID makeMptID(std::uint32_t const sequence, AccountID const &account)
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.
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
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 > immutableFlags
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::uint16_t transferFee
std::optional< std::uint64_t > maxAmt
std::optional< std::uint32_t > immutableFlags
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::uint32_t > immutableFlags
std::optional< std::uint16_t > transferFee
std::optional< std::uint32_t > flags
std::optional< std::variant< Account, AccountID > > holder
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...