xrpld
Loading...
Searching...
No Matches
libxrpl/protocol/ConfidentialTransfer.cpp
1#include <xrpl/protocol/ConfidentialTransfer.h>
2
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/beast/utility/instrumentation.h>
8#include <xrpl/protocol/AccountID.h>
9#include <xrpl/protocol/LedgerFormats.h>
10#include <xrpl/protocol/Protocol.h>
11#include <xrpl/protocol/SField.h>
12#include <xrpl/protocol/STBlob.h>
13#include <xrpl/protocol/STLedgerEntry.h>
14#include <xrpl/protocol/STObject.h>
15#include <xrpl/protocol/TER.h>
16#include <xrpl/protocol/UintTypes.h>
17
18#include <openssl/rand.h>
19#include <utility/mpt_utility.h>
20
21#include <mpt_protocol.h>
22#include <secp256k1.h>
23#include <secp256k1_mpt.h>
24
25#include <cstddef>
26#include <cstdint>
27#include <cstring>
28#include <optional>
29#include <stdexcept>
30#include <vector>
31
32namespace xrpl {
33namespace {
34
35account_id
36toAccountId(AccountID const& account)
37{
38 account_id res;
39 std::memcpy(res.bytes, account.data(), kMPT_ACCOUNT_ID_SIZE);
40 return res;
41}
42
43mpt_issuance_id
44toIssuanceId(UInt192 const& issuance)
45{
46 mpt_issuance_id res;
47 std::memcpy(res.bytes, issuance.data(), kMPT_ISSUANCE_ID_SIZE);
48 return res;
49}
50
57mpt_confidential_participant
58toParticipant(ConfidentialRecipient const& r)
59{
60 mpt_confidential_participant p{};
61 std::memcpy(p.pubkey, r.publicKey.data(), kEcPubKeyLength);
62 std::memcpy(p.ciphertext, r.encryptedAmount.data(), kEcGamalEncryptedTotalLength);
63 return p;
64}
65
66} // namespace
67
70 AccountID const& account,
71 UInt192 const& issuanceID,
72 std::uint32_t sequence,
73 AccountID const& destination,
74 std::uint32_t version)
75{
76 UInt256 result;
77 mpt_get_send_context_hash(
78 toAccountId(account),
79 toIssuanceId(issuanceID),
80 sequence,
81 toAccountId(destination),
82 version,
83 result.data());
84 return result;
85}
86
89 AccountID const& account,
90 UInt192 const& issuanceID,
91 std::uint32_t sequence,
92 AccountID const& holder)
93{
94 UInt256 result;
95 mpt_get_clawback_context_hash(
96 toAccountId(account),
97 toIssuanceId(issuanceID),
98 sequence,
99 toAccountId(holder),
100 result.data());
101 return result;
102}
103
105getConvertContextHash(AccountID const& account, UInt192 const& issuanceID, std::uint32_t sequence)
106{
107 UInt256 result;
108 mpt_get_convert_context_hash(
109 toAccountId(account), toIssuanceId(issuanceID), sequence, result.data());
110 return result;
111}
112
115 AccountID const& account,
116 UInt192 const& issuanceID,
117 std::uint32_t sequence,
118 std::uint32_t version)
119{
120 UInt256 result;
121 mpt_get_convert_back_context_hash(
122 toAccountId(account), toIssuanceId(issuanceID), sequence, version, result.data());
123 return result;
124}
125
127makeEcPair(Slice const& buffer)
128{
129 if (buffer.length() != 2 * kEcCiphertextComponentLength)
130 {
131 // LCOV_EXCL_START
132 UNREACHABLE("xrpl::makeEcPair : callers must pre-validate ciphertext length");
133 return std::nullopt;
134 // LCOV_EXCL_STOP
135 }
136
137 auto parsePubKey = [](Slice const& slice, secp256k1_pubkey& out) {
138 return secp256k1_ec_pubkey_parse(secp256k1Context(), &out, slice.data(), slice.length());
139 };
140
141 Slice const s1{buffer.data(), kEcCiphertextComponentLength};
143
144 EcPair pair{};
145 if (parsePubKey(s1, pair.c1) != 1 || parsePubKey(s2, pair.c2) != 1)
146 return std::nullopt;
147
148 return pair;
149}
150
153{
154 auto serializePubKey = [](secp256k1_pubkey const& pub, unsigned char* out) {
155 size_t outLen = kEcCiphertextComponentLength; // 33 bytes
156 auto const ret = secp256k1_ec_pubkey_serialize(
157 secp256k1Context(), out, &outLen, &pub, SECP256K1_EC_COMPRESSED);
158 return ret == 1 && outLen == kEcCiphertextComponentLength;
159 };
160
162 auto const ptr = buffer.data();
163 bool const res1 = serializePubKey(pair.c1, ptr);
164 bool const res2 = serializePubKey(pair.c2, ptr + kEcCiphertextComponentLength);
165
166 if (!res1 || !res2)
167 return std::nullopt;
168
169 return buffer;
170}
171
172bool
174{
175 return makeEcPair(buffer).has_value();
176}
177
178bool
180{
181 if (buffer.size() != kCompressedEcPointLength)
182 return false;
183
184 // Compressed EC points must start with 0x02 or 0x03
185 if (buffer[0] != kEcCompressedPrefixEvenY && buffer[0] != kEcCompressedPrefixOddY)
186 return false;
187
188 secp256k1_pubkey point;
189 return secp256k1_ec_pubkey_parse(secp256k1Context(), &point, buffer.data(), buffer.size()) == 1;
190}
191
193homomorphicAdd(Slice const& a, Slice const& b)
194{
196 return std::nullopt;
197
198 auto const pairA = makeEcPair(a);
199 auto const pairB = makeEcPair(b);
200
201 if (!pairA || !pairB)
202 return std::nullopt;
203
204 EcPair sum{};
205 if (auto res = secp256k1_elgamal_add(
206 secp256k1Context(), &sum.c1, &sum.c2, &pairA->c1, &pairA->c2, &pairB->c1, &pairB->c2);
207 res != 1)
208 {
209 return std::nullopt;
210 }
211
212 return serializeEcPair(sum);
213}
214
216homomorphicSubtract(Slice const& a, Slice const& b)
217{
219 return std::nullopt;
220
221 auto const pairA = makeEcPair(a);
222 auto const pairB = makeEcPair(b);
223
224 if (!pairA || !pairB)
225 return std::nullopt;
226
227 EcPair diff{};
228 if (auto const res = secp256k1_elgamal_subtract(
229 secp256k1Context(), &diff.c1, &diff.c2, &pairA->c1, &pairA->c2, &pairB->c1, &pairB->c2);
230 res != 1)
231 {
232 return std::nullopt;
233 }
234
235 return serializeEcPair(diff);
236}
237
239rerandomizeCiphertext(Slice const& ciphertext, Slice const& pubKeySlice, Slice const& randomness)
240{
241 auto zero = encryptAmount(0, pubKeySlice, randomness);
242 if (!zero)
243 return std::nullopt;
244
245 return homomorphicAdd(ciphertext, *zero);
246}
247
248Buffer
250{
251 unsigned char blindingFactor[kEcBlindingFactorLength];
252
253 // todo: might need to be updated using another RNG
254 if (RAND_bytes(blindingFactor, kEcBlindingFactorLength) != 1)
255 Throw<std::runtime_error>("Failed to generate random number");
256
257 return Buffer(blindingFactor, kEcBlindingFactorLength);
258}
259
261encryptAmount(uint64_t const amt, Slice const& pubKeySlice, Slice const& blindingFactor)
262{
263 if (blindingFactor.size() != kEcBlindingFactorLength || pubKeySlice.size() != kEcPubKeyLength)
264 return std::nullopt;
265
267 if (mpt_encrypt_amount(amt, pubKeySlice.data(), blindingFactor.data(), out.data()) != 0)
268 return std::nullopt;
269
270 return out;
271}
272
274encryptCanonicalZeroAmount(Slice const& pubKeySlice, AccountID const& account, MPTID const& mptId)
275{
276 if (pubKeySlice.size() != kEcPubKeyLength)
277 {
278 // LCOV_EXCL_START
279 UNREACHABLE(
280 "xrpl::encryptCanonicalZeroAmount : callers must pre-validate public key length");
281 return std::nullopt;
282 // LCOV_EXCL_STOP
283 }
284
285 EcPair pair{};
286 secp256k1_pubkey pubKey;
287 if (auto res = secp256k1_ec_pubkey_parse(
288 secp256k1Context(), &pubKey, pubKeySlice.data(), kEcPubKeyLength);
289 res != 1)
290 {
291 // LCOV_EXCL_START
292 UNREACHABLE(
293 "xrpl::encryptCanonicalZeroAmount : public key read from the ledger must already be "
294 "valid");
295 return std::nullopt;
296 // LCOV_EXCL_STOP
297 }
298
299 if (auto res = generate_canonical_encrypted_zero(
300 secp256k1Context(), &pair.c1, &pair.c2, &pubKey, account.data(), mptId.data());
301 res != 1)
302 {
303 // LCOV_EXCL_START
304 UNREACHABLE(
305 "xrpl::encryptCanonicalZeroAmount : canonical zero generation cannot fail for a "
306 "valid public key");
307 return std::nullopt;
308 // LCOV_EXCL_STOP
309 }
310
311 return serializeEcPair(pair);
312}
313
314TER
316 uint64_t const amount,
317 Slice const& blindingFactor,
318 ConfidentialRecipient const& holder,
319 ConfidentialRecipient const& issuer,
321{
322 if (blindingFactor.size() != kEcBlindingFactorLength ||
323 holder.publicKey.size() != kEcPubKeyLength ||
325 issuer.publicKey.size() != kEcPubKeyLength ||
327 {
328 // LCOV_EXCL_START
329 UNREACHABLE(
330 "xrpl::verifyRevealedAmount : callers must pre-validate holder/issuer field lengths");
331 return tecINTERNAL;
332 // LCOV_EXCL_STOP
333 }
334
335 auto const holderP = toParticipant(holder);
336 auto const issuerP = toParticipant(issuer);
337 mpt_confidential_participant auditorP{};
338 mpt_confidential_participant const* auditorPtr = nullptr;
339 if (auditor)
340 {
341 if (auditor->publicKey.size() != kEcPubKeyLength ||
342 auditor->encryptedAmount.size() != kEcGamalEncryptedTotalLength)
343 {
344 // LCOV_EXCL_START
345 UNREACHABLE(
346 "xrpl::verifyRevealedAmount : callers must pre-validate auditor field lengths");
347 return tecINTERNAL;
348 // LCOV_EXCL_STOP
349 }
350 auditorP = toParticipant(*auditor);
351 auditorPtr = &auditorP;
352 }
353
354 if (mpt_verify_revealed_amount(amount, blindingFactor.data(), &holderP, &issuerP, auditorPtr) !=
355 0)
356 {
357 return tecBAD_PROOF;
358 }
359
360 return tesSUCCESS;
361}
362
363NotTEC
365{
366 // Current usage of this function is only for ConfidentialMPTConvert and
367 // ConfidentialMPTConvertBack transactions, which already enforce that these fields
368 // are present.
369 if (!object.isFieldPresent(sfHolderEncryptedAmount) ||
370 !object.isFieldPresent(sfIssuerEncryptedAmount))
371 {
372 // LCOV_EXCL_START
373 UNREACHABLE(
374 "xrpl::checkEncryptedAmountFormat : callers already enforce that these fields are "
375 "present");
376 return temMALFORMED;
377 // LCOV_EXCL_STOP
378 }
379
380 if (object[sfHolderEncryptedAmount].length() != kEcGamalEncryptedTotalLength ||
381 object[sfIssuerEncryptedAmount].length() != kEcGamalEncryptedTotalLength)
382 {
383 return temBAD_CIPHERTEXT;
384 }
385
386 bool const hasAuditor = object.isFieldPresent(sfAuditorEncryptedAmount);
387 if (hasAuditor && object[sfAuditorEncryptedAmount].length() != kEcGamalEncryptedTotalLength)
388 return temBAD_CIPHERTEXT;
389
390 if (!isValidCiphertext(object[sfHolderEncryptedAmount]) ||
391 !isValidCiphertext(object[sfIssuerEncryptedAmount]))
392 {
393 return temBAD_CIPHERTEXT;
394 }
395
396 if (hasAuditor && !isValidCiphertext(object[sfAuditorEncryptedAmount]))
397 return temBAD_CIPHERTEXT;
398
399 return tesSUCCESS;
400}
401
402bool
403isIssuerMirrorCurrent(SLE const& issuance, SLE const& mptoken)
404{
405 XRPL_ASSERT(
406 issuance.getType() == ltMPTOKEN_ISSUANCE,
407 "xrpl::isIssuerMirrorCurrent : issuance MPTokenIssuance object");
408 XRPL_ASSERT(
409 mptoken.getType() == ltMPTOKEN, "xrpl::isIssuerMirrorCurrent : mptoken MPToken object");
410
411 return mptoken.isFieldPresent(sfIssuerEncryptedBalance) &&
412 mptoken[~sfIssuerKeyMirrorEpoch].value_or(0) == issuance[~sfIssuerKeyEpoch].value_or(0);
413}
414
415bool
416isAuditorMirrorCurrent(SLE const& issuance, SLE const& mptoken)
417{
418 XRPL_ASSERT(
419 issuance.getType() == ltMPTOKEN_ISSUANCE,
420 "xrpl::isAuditorMirrorCurrent : issuance MPTokenIssuance object");
421 XRPL_ASSERT(
422 mptoken.getType() == ltMPTOKEN, "xrpl::isAuditorMirrorCurrent : mptoken MPToken object");
423
424 if (!issuance.isFieldPresent(sfAuditorEncryptionKey))
425 return true;
426
427 return mptoken.isFieldPresent(sfAuditorEncryptedBalance) &&
428 mptoken[~sfAuditorKeyMirrorEpoch].value_or(0) == issuance[~sfAuditorKeyEpoch].value_or(0);
429}
430
431bool
432areMirrorsCurrent(SLE const& issuance, SLE const& mptoken)
433{
434 return isIssuerMirrorCurrent(issuance, mptoken) && isAuditorMirrorCurrent(issuance, mptoken);
435}
436
437void
438setIssuerMirrorEpoch(SLE const& issuance, SLE& mptoken)
439{
440 XRPL_ASSERT(
441 issuance.getType() == ltMPTOKEN_ISSUANCE,
442 "xrpl::setIssuerMirrorEpoch : issuance MPTokenIssuance object");
443 XRPL_ASSERT(
444 mptoken.getType() == ltMPTOKEN, "xrpl::setIssuerMirrorEpoch : mptoken MPToken object");
445
446 // Unlike the auditor mirror, the issuer mirror is not optional: every
447 // confidential MPToken carries one, so there is no existence check here.
448 if (auto const epoch = issuance[~sfIssuerKeyEpoch].value_or(0); epoch != 0)
449 mptoken[sfIssuerKeyMirrorEpoch] = epoch;
450}
451
452void
453setAuditorMirrorEpoch(SLE const& issuance, SLE& mptoken)
454{
455 XRPL_ASSERT(
456 issuance.getType() == ltMPTOKEN_ISSUANCE,
457 "xrpl::setAuditorMirrorEpoch : issuance MPTokenIssuance object");
458 XRPL_ASSERT(
459 mptoken.getType() == ltMPTOKEN, "xrpl::setAuditorMirrorEpoch : mptoken MPToken object");
460
461 if (!mptoken.isFieldPresent(sfAuditorEncryptedBalance))
462 return;
463
464 if (auto const epoch = issuance[~sfAuditorKeyEpoch].value_or(0); epoch != 0)
465 mptoken[sfAuditorKeyMirrorEpoch] = epoch;
466}
467
468void
469setMirrorEpochs(SLE const& issuance, SLE& mptoken)
470{
471 setIssuerMirrorEpoch(issuance, mptoken);
472 setAuditorMirrorEpoch(issuance, mptoken);
473}
474
475TER
476verifySchnorrProof(Slice const& pubKeySlice, Slice const& proofSlice, UInt256 const& contextHash)
477{
478 if (proofSlice.size() != kEcSchnorrProofLength || pubKeySlice.size() != kEcPubKeyLength)
479 {
480 // LCOV_EXCL_START
481 UNREACHABLE("xrpl::verifySchnorrProof : callers must pre-validate proof/public key length");
482 return tecINTERNAL;
483 // LCOV_EXCL_STOP
484 }
485
486 if (mpt_verify_convert_proof(proofSlice.data(), pubKeySlice.data(), contextHash.data()) != 0)
487 return tecBAD_PROOF;
488
489 return tesSUCCESS;
490}
491
492TER
494 uint64_t const amount,
495 Slice const& proof,
496 Slice const& pubKeySlice,
497 Slice const& ciphertext,
498 UInt256 const& contextHash)
499{
500 if (ciphertext.size() != kEcGamalEncryptedTotalLength ||
501 pubKeySlice.size() != kEcPubKeyLength || proof.size() != kEcClawbackProofLength)
502 {
503 // LCOV_EXCL_START
504 UNREACHABLE(
505 "xrpl::verifyClawbackProof : callers must pre-validate ciphertext/public "
506 "key/proof length");
507 return tecINTERNAL;
508 // LCOV_EXCL_STOP
509 }
510
511 if (mpt_verify_clawback_proof(
512 proof.data(), amount, pubKeySlice.data(), ciphertext.data(), contextHash.data()) != 0)
513 {
514 return tecBAD_PROOF;
515 }
516
517 return tesSUCCESS;
518}
519
520TER
522 Slice const& proof,
523 ConfidentialRecipient const& sender,
524 ConfidentialRecipient const& destination,
525 ConfidentialRecipient const& issuer,
527 Slice const& spendingBalance,
528 Slice const& amountCommitment,
529 Slice const& balanceCommitment,
530 UInt256 const& contextHash)
531{
532 auto const recipientCount = getConfidentialRecipientCount(auditor.has_value());
533 if (proof.size() != kEcSendProofLength || sender.publicKey.size() != kEcPubKeyLength ||
535 destination.publicKey.size() != kEcPubKeyLength ||
537 issuer.publicKey.size() != kEcPubKeyLength ||
539 spendingBalance.size() != kEcGamalEncryptedTotalLength ||
540 amountCommitment.size() != kEcPedersenCommitmentLength ||
541 balanceCommitment.size() != kEcPedersenCommitmentLength)
542 {
543 // LCOV_EXCL_START
544 UNREACHABLE(
545 "xrpl::verifySendProof : callers must pre-validate proof/participant/commitment "
546 "lengths");
547 return tecINTERNAL;
548 // LCOV_EXCL_STOP
549 }
550
552 participants.reserve(recipientCount);
553 participants.push_back(toParticipant(sender));
554 participants.push_back(toParticipant(destination));
555 participants.push_back(toParticipant(issuer));
556 if (auditor)
557 {
558 if (auditor->publicKey.size() != kEcPubKeyLength ||
559 auditor->encryptedAmount.size() != kEcGamalEncryptedTotalLength)
560 {
561 // LCOV_EXCL_START
562 UNREACHABLE("xrpl::verifySendProof : callers must pre-validate auditor field lengths");
563 return tecINTERNAL;
564 // LCOV_EXCL_STOP
565 }
566 participants.push_back(toParticipant(*auditor));
567 }
568 if (participants.size() != recipientCount)
569 {
570 // LCOV_EXCL_START
571 UNREACHABLE(
572 "xrpl::verifySendProof : participant count must match the requested recipient "
573 "count");
574 return tecINTERNAL;
575 // LCOV_EXCL_STOP
576 }
577
578 if (mpt_verify_send_proof(
579 proof.data(),
580 participants.data(),
581 recipientCount,
582 spendingBalance.data(),
583 amountCommitment.data(),
584 balanceCommitment.data(),
585 contextHash.data()) != 0)
586 {
587 return tecBAD_PROOF;
588 }
589
590 return tesSUCCESS;
591}
592
593TER
595 Slice const& proof,
596 Slice const& pubKeySlice,
597 Slice const& spendingBalance,
598 Slice const& balanceCommitment,
599 uint64_t amount,
600 UInt256 const& contextHash)
601{
602 if (proof.size() != kEcConvertBackProofLength || pubKeySlice.size() != kEcPubKeyLength ||
603 spendingBalance.size() != kEcGamalEncryptedTotalLength ||
604 balanceCommitment.size() != kEcPedersenCommitmentLength)
605 {
606 // LCOV_EXCL_START
607 UNREACHABLE(
608 "xrpl::verifyConvertBackProof : callers must pre-validate proof/public "
609 "key/balance/commitment lengths");
610 return tecINTERNAL;
611 // LCOV_EXCL_STOP
612 }
613
614 if (mpt_verify_convert_back_proof(
615 proof.data(),
616 pubKeySlice.data(),
617 spendingBalance.data(),
618 balanceCommitment.data(),
619 amount,
620 contextHash.data()) != 0)
621 {
622 return tecBAD_PROOF;
623 }
624
625 return tesSUCCESS;
626}
627
628} // namespace xrpl
pointer data()
Definition base_uint.h:117
Like std::vector<char> but better.
Definition Buffer.h:19
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
Definition Buffer.h:148
LedgerEntryType getType() const
bool isFieldPresent(SField const &field) const
Definition STObject.cpp:464
An immutable linear range of bytes.
Definition Slice.h:28
std::size_t length() const noexcept
Definition Slice.h:76
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
Definition Slice.h:88
std::size_t size() const noexcept
Returns the number of bytes in the storage.
Definition Slice.h:70
T data(T... args)
T memcpy(T... args)
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:220
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
bool areMirrorsCurrent(SLE const &issuance, SLE const &mptoken)
Checks whether each mirror a holder is required to have is encrypted under the issuance's currently r...
constexpr std::size_t kEcPubKeyLength
Length of EC public key (compressed).
Definition Protocol.h:485
constexpr std::uint8_t kEcCompressedPrefixEvenY
Compressed EC point prefix for even y-coordinate.
Definition Protocol.h:561
NotTEC checkEncryptedAmountFormat(STObject const &object)
Validates the format of encrypted amount fields in a transaction.
void setMirrorEpochs(SLE const &issuance, SLE &mptoken)
Set the holder's MPToken mirror epochs to match the issuance's current key epochs.
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.
constexpr std::size_t kEcBlindingFactorLength
Length of the EC blinding factor in bytes.
Definition Protocol.h:495
std::optional< Buffer > encryptCanonicalZeroAmount(Slice const &pubKeySlice, AccountID const &account, MPTID const &mptId)
Generates the canonical zero encryption for a specific MPToken.
UInt256 getConvertContextHash(AccountID const &account, UInt192 const &issuanceID, std::uint32_t sequence)
Generates the context hash for ConfidentialMPTConvert transactions.
constexpr std::size_t kCompressedEcPointLength
Length of EC point (compressed).
Definition Protocol.h:470
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.
bool isIssuerMirrorCurrent(SLE const &issuance, SLE const &mptoken)
Checks whether a holder's issuer mirror is encrypted under the issuance's currently registered issuer...
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 kEcClawbackProofLength
Length of the ZKProof for ConfidentialMPTClawback.
Definition Protocol.h:541
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.
Definition Protocol.h:566
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.
Definition Protocol.h:500
bool isAuditorMirrorCurrent(SLE const &issuance, SLE const &mptoken)
Checks whether a holder's auditor mirror is encrypted under the issuance's currently registered audit...
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.
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.
constexpr std::size_t kEcGamalEncryptedTotalLength
EC ElGamal ciphertext length: two compressed EC points concatenated.
Definition Protocol.h:480
TER verifyClawbackProof(uint64_t const amount, Slice const &proof, Slice const &pubKeySlice, Slice const &ciphertext, UInt256 const &contextHash)
Verifies a compact sigma clawback proof.
std::optional< Buffer > serializeEcPair(EcPair const &pair)
Serializes an EcPair into compressed form.
BaseUInt< 192 > UInt192
Definition base_uint.h:581
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.
Definition Protocol.h:535
STLedgerEntry SLE
bool isValidCiphertext(Slice const &buffer)
Verifies that a buffer contains two valid, parsable EC public keys.
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.
BaseUInt< 256 > UInt256
Definition base_uint.h:580
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:614
constexpr std::size_t kEcPedersenCommitmentLength
Length of Pedersen Commitment (compressed).
Definition Protocol.h:505
constexpr std::size_t kEcCiphertextComponentLength
Length of one compressed EC point component in an EC ElGamal ciphertext.
Definition Protocol.h:475
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 ...
Definition UintTypes.h:54
void setAuditorMirrorEpoch(SLE const &issuance, SLE &mptoken)
Set the holder's auditor mirror epoch to match the issuance's current auditor key epoch.
void setIssuerMirrorEpoch(SLE const &issuance, SLE &mptoken)
Set the holder's issuer mirror epoch to match the issuance's current issuer key epoch.
secp256k1_context const * secp256k1Context()
Definition secp256k1.h:9
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.
Definition AccountID.h:34
constexpr std::size_t kEcSendProofLength
192 bytes compact sigma proof + 754 bytes double bulletproof.
Definition Protocol.h:525
@ temBAD_CIPHERTEXT
Definition TER.h:134
@ temMALFORMED
Definition TER.h:75
TERSubset< CanCvtToTER > TER
Definition TER.h:654
@ tecINTERNAL
Definition TER.h:318
@ tecBAD_PROOF
Definition TER.h:376
TER verifySchnorrProof(Slice const &pubKeySlice, Slice const &proofSlice, UInt256 const &contextHash)
Verifies a Schnorr proof of knowledge of an ElGamal private key.
std::optional< Buffer > homomorphicAdd(Slice const &a, Slice const &b)
Homomorphically adds two ElGamal ciphertexts.
@ tesSUCCESS
Definition TER.h:250
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
Definition contract.h:52
T has_value(T... args)
T push_back(T... args)
T reserve(T... args)
T size(T... args)
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.