1#include <xrpl/protocol/ConfidentialTransfer.h>
3#include <xrpl/basics/Buffer.h>
4#include <xrpl/basics/Slice.h>
5#include <xrpl/basics/base_uint.h>
6#include <xrpl/basics/contract.h>
7#include <xrpl/protocol/AccountID.h>
8#include <xrpl/protocol/Protocol.h>
9#include <xrpl/protocol/SField.h>
10#include <xrpl/protocol/STObject.h>
11#include <xrpl/protocol/TER.h>
12#include <xrpl/protocol/UintTypes.h>
14#include <openssl/rand.h>
15#include <utility/mpt_utility.h>
17#include <mpt_protocol.h>
19#include <secp256k1_mpt.h>
40toIssuanceId(
uint192 const& issuance)
43 std::memcpy(res.bytes, issuance.data(), kMPT_ISSUANCE_ID_SIZE);
53mpt_confidential_participant
56 mpt_confidential_participant p{};
73 mpt_get_send_context_hash(
75 toIssuanceId(issuanceID),
77 toAccountId(destination),
91 mpt_get_clawback_context_hash(
93 toIssuanceId(issuanceID),
104 mpt_get_convert_context_hash(
105 toAccountId(account), toIssuanceId(issuanceID), sequence, result.
data());
117 mpt_get_convert_back_context_hash(
118 toAccountId(account), toIssuanceId(issuanceID), sequence, version, result.
data());
128 auto parsePubKey = [](
Slice const& slice, secp256k1_pubkey& out) {
136 if (parsePubKey(s1, pair.
c1) != 1 || parsePubKey(s2, pair.
c2) != 1)
145 auto serializePubKey = [](secp256k1_pubkey
const& pub,
unsigned char* out) {
147 auto const ret = secp256k1_ec_pubkey_serialize(
153 auto const ptr = buffer.
data();
154 bool const res1 = serializePubKey(pair.
c1, ptr);
179 secp256k1_pubkey point;
192 if (!pairA || !pairB)
196 if (
auto res = secp256k1_elgamal_add(
215 if (!pairA || !pairB)
219 if (
auto const res = secp256k1_elgamal_subtract(
258 if (mpt_encrypt_amount(amt, pubKeySlice.
data(), blindingFactor.
data(), out.
data()) != 0)
271 secp256k1_pubkey pubKey;
272 if (
auto res = secp256k1_ec_pubkey_parse(
279 if (
auto res = generate_canonical_encrypted_zero(
291 uint64_t
const amount,
292 Slice const& blindingFactor,
306 auto const holderP = toParticipant(holder);
307 auto const issuerP = toParticipant(issuer);
308 mpt_confidential_participant auditorP{};
309 mpt_confidential_participant
const* auditorPtr =
nullptr;
317 auditorP = toParticipant(*auditor);
318 auditorPtr = &auditorP;
321 if (mpt_verify_revealed_amount(amount, blindingFactor.
data(), &holderP, &issuerP, auditorPtr) !=
336 if (!
object.isFieldPresent(sfHolderEncryptedAmount) ||
337 !
object.isFieldPresent(sfIssuerEncryptedAmount))
348 bool const hasAuditor =
object.isFieldPresent(sfAuditorEncryptedAmount);
370 if (mpt_verify_convert_proof(proofSlice.
data(), pubKeySlice.
data(), contextHash.
data()) != 0)
378 uint64_t
const amount,
380 Slice const& pubKeySlice,
381 Slice const& ciphertext,
390 if (mpt_verify_clawback_proof(
391 proof.
data(), amount, pubKeySlice.
data(), ciphertext.
data(), contextHash.
data()) != 0)
406 Slice const& spendingBalance,
407 Slice const& amountCommitment,
408 Slice const& balanceCommitment,
426 participants.
reserve(recipientCount);
427 participants.
push_back(toParticipant(sender));
428 participants.
push_back(toParticipant(destination));
429 participants.
push_back(toParticipant(issuer));
437 participants.
push_back(toParticipant(*auditor));
439 if (participants.
size() != recipientCount)
442 if (mpt_verify_send_proof(
446 spendingBalance.
data(),
447 amountCommitment.
data(),
448 balanceCommitment.
data(),
449 contextHash.
data()) != 0)
460 Slice const& pubKeySlice,
461 Slice const& spendingBalance,
462 Slice const& balanceCommitment,
473 if (mpt_verify_convert_back_proof(
476 spendingBalance.
data(),
477 balanceCommitment.
data(),
479 contextHash.
data()) != 0)
Like std::vector<char> but better.
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
An immutable linear range of bytes.
std::size_t length() const noexcept
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.
Keylet account(AccountID const &id) noexcept
AccountID root.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
constexpr std::size_t kEcPubKeyLength
Length of EC public key (compressed).
constexpr std::uint8_t kEcCompressedPrefixEvenY
Compressed EC point prefix for even y-coordinate.
NotTEC checkEncryptedAmountFormat(STObject const &object)
Validates the format of encrypted amount fields in a transaction.
static auto sum(TCollection const &col)
std::optional< Buffer > rerandomizeCiphertext(Slice const &ciphertext, Slice const &pubKeySlice, Slice const &randomness)
Re-randomizes an ElGamal ciphertext without changing its plaintext.
TER verifySchnorrProof(Slice const &pubKeySlice, Slice const &proofSlice, uint256 const &contextHash)
Verifies a Schnorr proof of knowledge of an ElGamal private key.
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.
constexpr std::size_t kCompressedEcPointLength
Length of EC point (compressed).
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.
constexpr std::uint8_t kEcCompressedPrefixOddY
Compressed EC point prefix for odd y-coordinate.
bool isValidCompressedECPoint(Slice const &buffer)
Verifies that a buffer contains a valid, parsable compressed EC point.
constexpr std::size_t kEcSchnorrProofLength
Length of Schnorr ZKProof for public key registration (compact form) in bytes.
constexpr uint8_t getConfidentialRecipientCount(bool hasAuditor)
Returns the number of recipients in a confidential transfer.
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::optional< Buffer > serializeEcPair(EcPair const &pair)
Serializes an EcPair into compressed form.
TER verifyRevealedAmount(uint64_t const amount, Slice const &blindingFactor, ConfidentialRecipient const &holder, ConfidentialRecipient const &issuer, std::optional< ConfidentialRecipient > const &auditor)
Verifies revealed amount encryptions for all recipients.
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.
bool isValidCiphertext(Slice const &buffer)
Verifies that a buffer contains two valid, parsable EC public keys.
TERSubset< CanCvtToNotTEC > NotTEC
constexpr std::size_t kEcPedersenCommitmentLength
Length of Pedersen Commitment (compressed).
constexpr std::size_t kEcCiphertextComponentLength
Length of one compressed EC point component in an EC ElGamal ciphertext.
std::optional< Buffer > homomorphicSubtract(Slice const &a, Slice const &b)
Homomorphically subtracts two ElGamal ciphertexts.
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).
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
TER verifyConvertBackProof(Slice const &proof, Slice const &pubKeySlice, Slice const &spendingBalance, Slice const &balanceCommitment, uint64_t amount, uint256 const &contextHash)
Verifies all zero-knowledge proofs for a ConfidentialMPTConvertBack 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.
TERSubset< CanCvtToTER > TER
std::optional< Buffer > homomorphicAdd(Slice const &a, Slice const &b)
Homomorphically adds two ElGamal ciphertexts.
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
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.
TER verifyClawbackProof(uint64_t const amount, Slice const &proof, Slice const &pubKeySlice, Slice const &ciphertext, uint256 const &contextHash)
Verifies a compact sigma clawback proof.
Bundles an ElGamal public key with its associated encrypted amount.
Slice encryptedAmount
The encrypted amount ciphertext (size=xrpl::kEcGamalEncryptedTotalLength).
Slice publicKey
The recipient's ElGamal public key (size=xrpl::kEcPubKeyLength).
Holds two secp256k1 public key components representing an ElGamal ciphertext (C1, C2).
secp256k1_pubkey c2
Second ElGamal ciphertext component.
secp256k1_pubkey c1
First ElGamal ciphertext component.