1#include <xrpl/tx/transactors/token/ConfidentialMPTSend.h>
3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/Slice.h>
5#include <xrpl/core/ServiceRegistry.h>
6#include <xrpl/ledger/ReadView.h>
7#include <xrpl/ledger/helpers/CredentialHelpers.h>
8#include <xrpl/ledger/helpers/TokenHelpers.h>
9#include <xrpl/protocol/ConfidentialTransfer.h>
10#include <xrpl/protocol/Feature.h>
11#include <xrpl/protocol/Indexes.h>
12#include <xrpl/protocol/LedgerFormats.h>
13#include <xrpl/protocol/Protocol.h>
14#include <xrpl/protocol/SField.h>
15#include <xrpl/protocol/TER.h>
16#include <xrpl/protocol/XRPAmount.h>
17#include <xrpl/tx/Transactor.h>
37 auto const account = ctx.
tx[sfAccount];
42 if (account == issuer)
46 if (account == ctx.
tx[sfDestination])
50 if (ctx.
tx[sfDestination] == issuer)
110 if (!sleSenderMPToken || !sleDestinationMPToken || !sleIssuance)
120 .publicKey = (*sleIssuance)[sfAuditorEncryptionKey],
121 .encryptedAmount = ctx.
tx[sfAuditorEncryptedAmount],
127 ctx.
tx[sfMPTokenIssuanceID],
129 ctx.
tx[sfDestination],
130 (*sleSenderMPToken)[~sfConfidentialBalanceVersion].value_or(0));
135 .publicKey = (*sleSenderMPToken)[sfHolderEncryptionKey],
136 .encryptedAmount = ctx.tx[sfSenderEncryptedAmount],
139 .publicKey = (*sleDestinationMPToken)[sfHolderEncryptionKey],
140 .encryptedAmount = ctx.tx[sfDestinationEncryptedAmount],
143 .publicKey = (*sleIssuance)[sfIssuerEncryptionKey],
144 .encryptedAmount = ctx.tx[sfIssuerEncryptedAmount],
147 (*sleSenderMPToken)[sfConfidentialBalanceSpending],
148 ctx.
tx[sfAmountCommitment],
149 ctx.
tx[sfBalanceCommitment],
159 auto const account = ctx.
tx[sfAccount];
164 auto const destination = ctx.
tx[sfDestination];
170 if (((sleDst->getFlags() & lsfRequireDestTag) != 0u) &&
177 auto const mptIssuanceID = ctx.
tx[sfMPTokenIssuanceID];
183 if (!sleIssuance->isFlag(lsfMPTCanTransfer))
187 if (!sleIssuance->isFlag(lsfMPTCanHoldConfidentialBalance))
193 if ((*sleIssuance)[~sfTransferFee].value_or(0) > 0)
197 if (!sleIssuance->isFieldPresent(sfIssuerEncryptionKey))
201 bool const requiresAuditor = sleIssuance->isFieldPresent(sfAuditorEncryptionKey);
205 if (requiresAuditor != hasAuditor)
209 if (sleIssuance->getAccountID(sfIssuer) == ctx.
tx[sfAccount])
214 if (!sleSenderMPToken)
218 if (!sleSenderMPToken->isFieldPresent(sfHolderEncryptionKey) ||
219 !sleSenderMPToken->isFieldPresent(sfConfidentialBalanceSpending) ||
220 !sleSenderMPToken->isFieldPresent(sfIssuerEncryptedBalance))
227 if (!sleDestinationMPToken)
231 if (!sleDestinationMPToken->isFieldPresent(sfHolderEncryptionKey) ||
232 !sleDestinationMPToken->isFieldPresent(sfConfidentialBalanceInbox) ||
233 !sleDestinationMPToken->isFieldPresent(sfIssuerEncryptedBalance))
240 if (requiresAuditor &&
241 (!sleSenderMPToken->isFieldPresent(sfAuditorEncryptedBalance) ||
242 !sleDestinationMPToken->isFieldPresent(sfAuditorEncryptedBalance)))
248 MPTIssue const mptIssue(mptIssuanceID);
268 auto const preauthErr =
279 auto const mptIssuanceID =
ctx_.tx[sfMPTokenIssuanceID];
280 auto const destination =
ctx_.tx[sfDestination];
288 if (!sleSenderMPToken || !sleDestinationMPToken || !sleIssuance || !sleDestAcct)
297 auto const senderEc =
ctx_.tx[sfSenderEncryptedAmount];
298 auto const destEc =
ctx_.tx[sfDestinationEncryptedAmount];
299 auto const issuerEc =
ctx_.tx[sfIssuerEncryptedAmount];
300 auto const proof =
ctx_.tx[sfZKProof];
303 auto const auditorEc =
ctx_.tx[~sfAuditorEncryptedAmount];
307 auto const curSpending = (*sleSenderMPToken)[sfConfidentialBalanceSpending];
312 JLOG(
ctx_.journal.error())
313 <<
"ConfidentialMPTSend failed homomorphic subtract for sender spending balance.";
318 (*sleSenderMPToken)[sfConfidentialBalanceSpending] = std::move(*newSpending);
323 auto const curIssuerEnc = (*sleSenderMPToken)[sfIssuerEncryptedBalance];
328 JLOG(
ctx_.journal.error())
329 <<
"ConfidentialMPTSend failed homomorphic subtract for sender issuer balance.";
334 (*sleSenderMPToken)[sfIssuerEncryptedBalance] = std::move(*newIssuerEnc);
340 auto const curAuditorEnc = (*sleSenderMPToken)[sfAuditorEncryptedBalance];
345 JLOG(
ctx_.journal.error())
346 <<
"ConfidentialMPTSend failed homomorphic subtract for sender auditor balance.";
351 (*sleSenderMPToken)[sfAuditorEncryptedBalance] = std::move(*newAuditorEnc);
357 destEc, (*sleDestinationMPToken)[sfHolderEncryptionKey], sendChallenge);
358 if (!rerandomizedDestEc)
361 auto const curInbox = (*sleDestinationMPToken)[sfConfidentialBalanceInbox];
366 JLOG(
ctx_.journal.error())
367 <<
"ConfidentialMPTSend failed homomorphic add for destination inbox.";
372 (*sleDestinationMPToken)[sfConfidentialBalanceInbox] = std::move(*newInbox);
377 auto rerandomizedIssuerEc =
379 if (!rerandomizedIssuerEc)
382 auto const curIssuerEnc = (*sleDestinationMPToken)[sfIssuerEncryptedBalance];
383 auto newIssuerEnc =
homomorphicAdd(curIssuerEnc, *rerandomizedIssuerEc);
387 JLOG(
ctx_.journal.error())
388 <<
"ConfidentialMPTSend failed homomorphic add for destination issuer balance.";
393 (*sleDestinationMPToken)[sfIssuerEncryptedBalance] = std::move(*newIssuerEnc);
400 *auditorEc, (*sleIssuance)[sfAuditorEncryptionKey], sendChallenge);
401 if (!rerandomizedAuditorEc)
404 auto const curAuditorEnc = (*sleDestinationMPToken)[sfAuditorEncryptedBalance];
405 auto newAuditorEnc =
homomorphicAdd(curAuditorEnc, *rerandomizedAuditorEc);
409 JLOG(
ctx_.journal.error())
410 <<
"ConfidentialMPTSend failed homomorphic add for destination auditor balance.";
415 (*sleDestinationMPToken)[sfAuditorEncryptedBalance] = std::move(*newAuditorEnc);
A generic endpoint for log messages.
virtual SLE::pointer peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
virtual void update(SLE::ref sle)=0
Indicate changes to a peeked SLE.
void visitInvariantEntry(bool isDelete, std::shared_ptr< SLE const > const &before, std::shared_ptr< SLE const > const &after) override
static TER preclaim(PreclaimContext const &ctx)
static XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
static bool checkExtraFeatures(PreflightContext const &ctx)
bool finalizeInvariants(STTx const &tx, TER result, XRPAmount fee, ReadView const &view, beast::Journal const &j) override
Check transaction-specific post-conditions after all entries have been visited.
static NotTEC preflight(PreflightContext const &ctx)
AccountID const & getIssuer() const
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
virtual SLE::const_pointer read(Keylet const &k) const =0
Return the state item associated with a key.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
bool isFieldPresent(SField const &field) const
SeqProxy getSeqProxy() const
constexpr std::uint32_t value() const
An immutable linear range of bytes.
static XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
AccountID const accountID_
NotTEC checkFields(STTx const &tx, beast::Journal j)
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
static TER verifySendProofs(PreclaimContext const &ctx, std::shared_ptr< SLE const > const &sleSenderMPToken, std::shared_ptr< SLE const > const &sleDestinationMPToken, std::shared_ptr< SLE const > const &sleIssuance)
Keylet mptokenIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Keylet account(AccountID const &id) noexcept
AccountID root.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::optional< Buffer > rerandomizeCiphertext(Slice const &ciphertext, Slice const &pubKeySlice, Slice const &randomness)
Re-randomizes an ElGamal ciphertext without changing its plaintext.
constexpr std::size_t kEcBlindingFactorLength
Length of the EC blinding factor in bytes.
constexpr std::uint32_t kConfidentialFeeMultiplier
Extra base fee multiplier charged to confidential MPT transactions.
TER checkFrozen(ReadView const &view, AccountID const &account, Issue const &issue)
bool isValidCompressedECPoint(Slice const &buffer)
Verifies that a buffer contains a valid, parsable compressed EC point.
constexpr std::size_t kEcGamalEncryptedTotalLength
EC ElGamal ciphertext length: two compressed EC points concatenated.
bool isValidCiphertext(Slice const &buffer)
Verifies that a buffer contains two valid, parsable EC public keys.
TERSubset< CanCvtToNotTEC > NotTEC
std::optional< Buffer > homomorphicSubtract(Slice const &a, Slice const &b)
Homomorphically subtracts two ElGamal ciphertexts.
TER cleanupExpiredCredentials(STTx const &tx, ApplyView &view, beast::Journal j)
Remove expired credentials referenced by the transaction.
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
TERSubset< CanCvtToTER > TER
TER requireAuth(ReadView const &view, MPTIssue const &mptIssue, AccountID const &account, AuthType authType=AuthType::Legacy, std::uint8_t depth=0)
Check if the account lacks required authorization for MPT.
void incrementConfidentialVersion(STObject &mptoken)
Increments the confidential balance version counter on an MPToken.
std::optional< Buffer > homomorphicAdd(Slice const &a, Slice const &b)
Homomorphically adds two ElGamal ciphertexts.
TER checkDepositPreauth(STTx const &tx, ReadView const &view, AccountID const &src, AccountID const &dst, std::shared_ptr< SLE const > const &sleDst, beast::Journal j)
Check whether src is authorized to deposit to dst.
TER verifySendProof(Slice const &proof, ConfidentialRecipient const &sender, ConfidentialRecipient const &destination, ConfidentialRecipient const &issuer, std::optional< ConfidentialRecipient > const &auditor, Slice const &spendingBalance, Slice const &amountCommitment, Slice const &balanceCommitment, uint256 const &contextHash)
Verifies all zero-knowledge proofs for a ConfidentialMPTSend transaction.
Bundles an ElGamal public key with its associated encrypted amount.
State information when determining if a tx is likely to claim a fee.
State information when preflighting a tx.