Skip to content

Commit fe5934f

Browse files
Merge branch 'ripple/confidential-transfer' into add_Replay_tests_confidential_mpt
2 parents 40549de + c52d317 commit fe5934f

File tree

8 files changed

+50
-67
lines changed

8 files changed

+50
-67
lines changed

include/xrpl/protocol/ConfidentialTransfer.h

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,15 @@ incrementConfidentialVersion(STObject& mptoken)
5050
/**
5151
* @brief Adds common fields to a serializer for ZKP context hash generation.
5252
*
53-
* Serializes the transaction type, account, sequence number, and issuance ID
53+
* Serializes the transaction type, account, issuance ID and sequence/ticket number
5454
* into the provided serializer. These fields form the base of all context
5555
* hashes used in zero-knowledge proofs.
5656
*
5757
* @param s The serializer to append fields to.
5858
* @param txType The transaction type identifier.
5959
* @param account The account ID of the transaction sender.
60-
* @param sequence The transaction sequence number.
6160
* @param issuanceID The MPToken Issuance ID.
61+
* @param sequence The transaction sequence number or ticket number.
6262
*/
6363
void
6464
addCommonZKPFields(
@@ -75,17 +75,17 @@ addCommonZKPFields(
7575
* this specific send transaction, preventing proof reuse across transactions.
7676
*
7777
* @param account The sender's account ID.
78-
* @param sequence The transaction sequence number.
7978
* @param issuanceID The MPToken Issuance ID.
79+
* @param sequence The transaction sequence number or ticket number.
8080
* @param destination The destination account ID.
8181
* @param version The sender's confidential balance version.
8282
* @return A 256-bit context hash unique to this transaction.
8383
*/
8484
uint256
8585
getSendContextHash(
8686
AccountID const& account,
87-
std::uint32_t sequence,
8887
uint192 const& issuanceID,
88+
std::uint32_t sequence,
8989
AccountID const& destination,
9090
std::uint32_t version);
9191

@@ -96,18 +96,16 @@ getSendContextHash(
9696
* specific clawback transaction.
9797
*
9898
* @param account The issuer's account ID.
99-
* @param sequence The transaction sequence number.
10099
* @param issuanceID The MPToken Issuance ID.
101-
* @param amount The amount being clawed back.
100+
* @param sequence The transaction sequence number or ticket number.
102101
* @param holder The holder's account ID being clawed back from.
103102
* @return A 256-bit context hash unique to this transaction.
104103
*/
105104
uint256
106105
getClawbackContextHash(
107106
AccountID const& account,
108-
std::uint32_t sequence,
109107
uint192 const& issuanceID,
110-
std::uint64_t amount,
108+
std::uint32_t sequence,
111109
AccountID const& holder);
112110

113111
/**
@@ -117,17 +115,12 @@ getClawbackContextHash(
117115
* registration) to this specific convert transaction.
118116
*
119117
* @param account The holder's account ID.
120-
* @param sequence The transaction sequence number.
121118
* @param issuanceID The MPToken Issuance ID.
122-
* @param amount The amount being converted to confidential.
119+
* @param sequence The transaction sequence number or a ticket number.
123120
* @return A 256-bit context hash unique to this transaction.
124121
*/
125122
uint256
126-
getConvertContextHash(
127-
AccountID const& account,
128-
std::uint32_t sequence,
129-
uint192 const& issuanceID,
130-
std::uint64_t amount);
123+
getConvertContextHash(AccountID const& account, uint192 const& issuanceID, std::uint32_t sequence);
131124

132125
/**
133126
* @brief Generates the context hash for ConfidentialMPTConvertBack transactions.
@@ -136,18 +129,16 @@ getConvertContextHash(
136129
* this specific convert-back transaction.
137130
*
138131
* @param account The holder's account ID.
139-
* @param sequence The transaction sequence number.
140132
* @param issuanceID The MPToken Issuance ID.
141-
* @param amount The amount being converted back to public.
133+
* @param sequence The transaction sequence number or a ticket number.
142134
* @param version The holder's confidential balance version.
143135
* @return A 256-bit context hash unique to this transaction.
144136
*/
145137
uint256
146138
getConvertBackContextHash(
147139
AccountID const& account,
148-
std::uint32_t sequence,
149140
uint192 const& issuanceID,
150-
std::uint64_t amount,
141+
std::uint32_t sequence,
151142
std::uint32_t version);
152143

153144
/**

src/libxrpl/protocol/ConfidentialTransfer.cpp

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,28 @@ addCommonZKPFields(
1212
Serializer& s,
1313
std::uint16_t txType,
1414
AccountID const& account,
15-
std::uint32_t sequence,
16-
uint192 const& issuanceID)
15+
uint192 const& issuanceID,
16+
std::uint32_t sequence)
1717
{
18+
// TxCommonHash = hash(TxType || Account || IssuanceID || SequenceOrTicket)
1819
s.add16(txType);
1920
s.addBitString(account);
20-
s.add32(sequence);
2121
s.addBitString(issuanceID);
22+
s.add32(sequence);
2223
}
2324

2425
uint256
2526
getSendContextHash(
2627
AccountID const& account,
27-
std::uint32_t sequence,
2828
uint192 const& issuanceID,
29+
std::uint32_t sequence,
2930
AccountID const& destination,
3031
std::uint32_t version)
3132
{
3233
Serializer s;
33-
addCommonZKPFields(s, ttCONFIDENTIAL_MPT_SEND, account, sequence, issuanceID);
34+
addCommonZKPFields(s, ttCONFIDENTIAL_MPT_SEND, account, issuanceID, sequence);
3435

36+
// TxSpecific = identity || freshness
3537
s.addBitString(destination);
3638
s.addInteger(version);
3739

@@ -41,43 +43,45 @@ getSendContextHash(
4143
uint256
4244
getClawbackContextHash(
4345
AccountID const& account,
44-
std::uint32_t sequence,
4546
uint192 const& issuanceID,
46-
std::uint64_t amount,
47+
std::uint32_t sequence,
4748
AccountID const& holder)
4849
{
4950
Serializer s;
50-
addCommonZKPFields(s, ttCONFIDENTIAL_MPT_CLAWBACK, account, sequence, issuanceID);
51+
addCommonZKPFields(s, ttCONFIDENTIAL_MPT_CLAWBACK, account, issuanceID, sequence);
5152

52-
s.add64(amount);
53+
// TxSpecific = identity || freshness
5354
s.addBitString(holder);
55+
s.addInteger(0);
5456

5557
return s.getSHA512Half();
5658
}
5759

5860
uint256
59-
getConvertContextHash(AccountID const& account, std::uint32_t sequence, uint192 const& issuanceID, std::uint64_t amount)
61+
getConvertContextHash(AccountID const& account, uint192 const& issuanceID, std::uint32_t sequence)
6062
{
6163
Serializer s;
62-
addCommonZKPFields(s, ttCONFIDENTIAL_MPT_CONVERT, account, sequence, issuanceID);
64+
addCommonZKPFields(s, ttCONFIDENTIAL_MPT_CONVERT, account, issuanceID, sequence);
6365

64-
s.add64(amount);
66+
// TxSpecific = identity || freshness
67+
s.addBitString(account);
68+
s.addInteger(0);
6569

6670
return s.getSHA512Half();
6771
}
6872

6973
uint256
7074
getConvertBackContextHash(
7175
AccountID const& account,
72-
std::uint32_t sequence,
7376
uint192 const& issuanceID,
74-
std::uint64_t amount,
77+
std::uint32_t sequence,
7578
std::uint32_t version)
7679
{
7780
Serializer s;
78-
addCommonZKPFields(s, ttCONFIDENTIAL_MPT_CONVERT_BACK, account, sequence, issuanceID);
81+
addCommonZKPFields(s, ttCONFIDENTIAL_MPT_CONVERT_BACK, account, issuanceID, sequence);
7982

80-
s.add64(amount);
83+
// TxSpecific = identity || freshness
84+
s.addBitString(account);
8185
s.addInteger(version);
8286

8387
return s.getSHA512Half();

src/test/app/ConfidentialTransfer_test.cpp

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2068,8 +2068,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
20682068
Buffer const convertBlindingFactor = generateBlindingFactor();
20692069
auto const convertHolderCiphertext = mptAlice.encryptAmount(bob, maxMPTokenAmount, convertBlindingFactor);
20702070
auto const convertIssuerCiphertext = mptAlice.encryptAmount(alice, maxMPTokenAmount, convertBlindingFactor);
2071-
auto const convertContextHash =
2072-
getConvertContextHash(bob.id(), env.seq(bob), mptAlice.issuanceID(), maxMPTokenAmount);
2071+
auto const convertContextHash = getConvertContextHash(bob.id(), mptAlice.issuanceID(), env.seq(bob));
20732072
auto const schnorrProof = mptAlice.getSchnorrProof(bob, convertContextHash);
20742073
BEAST_EXPECT(schnorrProof.has_value());
20752074

@@ -2121,7 +2120,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
21212120
// Generate the proof using known spending balance value
21222121
auto const version = mptAlice.getMPTokenVersion(bob);
21232122
uint256 const convertBackContextHash =
2124-
getConvertBackContextHash(bob.id(), env.seq(bob), mptAlice.issuanceID(), convertBackAmt, version);
2123+
getConvertBackContextHash(bob.id(), mptAlice.issuanceID(), env.seq(bob), version);
21252124

21262125
Buffer const proof = mptAlice.getConvertBackProof(
21272126
bob,
@@ -3408,8 +3407,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
34083407
// The proof uses PC(1, rho) but the transaction submits PC(balance, rho).
34093408
// Verification fails because the proof doesn't match the submitted commitment.
34103409
{
3411-
uint256 const contextHash =
3412-
getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
3410+
uint256 const contextHash = getConvertBackContextHash(bob, mptAlice.issuanceID(), env.seq(bob), version);
34133411
Buffer const badPedersenCommitment = mptAlice.getPedersenCommitment(1, pcBlindingFactor);
34143412
Buffer const proof = mptAlice.getConvertBackProof(
34153413
bob,
@@ -3437,8 +3435,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
34373435
// The pedersen commitment PC = balance*G + rho*H requires the same rho
34383436
// used in proof generation. Using a different rho breaks the linkage.
34393437
{
3440-
uint256 const contextHash =
3441-
getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
3438+
uint256 const contextHash = getConvertBackContextHash(bob, mptAlice.issuanceID(), env.seq(bob), version);
34423439

34433440
Buffer const proof = mptAlice.getConvertBackProof(
34443441
bob,
@@ -3466,8 +3463,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
34663463
// The proof claims balance=1 but the encrypted spending balance contains
34673464
// the actual balance. Verification fails because the values don't match.
34683465
{
3469-
uint256 const contextHash =
3470-
getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
3466+
uint256 const contextHash = getConvertBackContextHash(bob, mptAlice.issuanceID(), env.seq(bob), version);
34713467

34723468
Buffer const proof = mptAlice.getConvertBackProof(
34733469
bob,
@@ -3496,8 +3492,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
34963492
// different pedersen commitment. Verification fails because the
34973493
// submitted commitment doesn't match what the proof was generated for.
34983494
{
3499-
uint256 const contextHash =
3500-
getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
3495+
uint256 const contextHash = getConvertBackContextHash(bob, mptAlice.issuanceID(), env.seq(bob), version);
35013496
Buffer const badPedersenCommitment = mptAlice.getPedersenCommitment(1, pcBlindingFactor);
35023497
Buffer const proof = mptAlice.getConvertBackProof(
35033498
bob,
@@ -3526,8 +3521,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
35263521
// sequence, issuanceID, amount, version). Using a different context hash
35273522
// makes the proof invalid for this transaction, preventing replay attacks.
35283523
{
3529-
uint256 const contextHash =
3530-
getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
3524+
uint256 const contextHash = getConvertBackContextHash(bob, mptAlice.issuanceID(), env.seq(bob), version);
35313525
uint256 const badContextHash{1};
35323526
Buffer const pedersenProof = mptAlice.getBalanceLinkageProof(
35333527
bob,
@@ -3560,8 +3554,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
35603554
// Test 6: Correct proof to verify the test setup is valid.
35613555
// All parameters are correct, so the transaction should succeed.
35623556
{
3563-
uint256 const contextHash =
3564-
getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
3557+
uint256 const contextHash = getConvertBackContextHash(bob, mptAlice.issuanceID(), env.seq(bob), version);
35653558

35663559
Buffer const proof = mptAlice.getConvertBackProof(
35673560
bob,
@@ -3675,8 +3668,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
36753668
// commitment was created with (balance - amount). The verifier computes
36763669
// PC_rem = PC - amount*G and checks if the bulletproof matches, which fails.
36773670
{
3678-
uint256 const contextHash =
3679-
getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
3671+
uint256 const contextHash = getConvertBackContextHash(bob, mptAlice.issuanceID(), env.seq(bob), version);
36803672

36813673
Buffer const bulletproof = mptAlice.getBulletproof(
36823674
{1}, // wrong remaining balance
@@ -3701,8 +3693,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
37013693
// commitment PC = (balance - amount)*G + rho*H. Using a different rho
37023694
// creates a commitment mismatch and verification fails.
37033695
{
3704-
uint256 const contextHash =
3705-
getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
3696+
uint256 const contextHash = getConvertBackContextHash(bob, mptAlice.issuanceID(), env.seq(bob), version);
37063697

37073698
Buffer const bulletproof = mptAlice.getBulletproof(
37083699
{*spendingBalance - amt},
@@ -3727,8 +3718,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
37273718
// sequence, issuanceID, amount, version). Using a different context hash
37283719
// makes the proof invalid for this transaction, preventing replay attacks.
37293720
{
3730-
uint256 const contextHash =
3731-
getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
3721+
uint256 const contextHash = getConvertBackContextHash(bob, mptAlice.issuanceID(), env.seq(bob), version);
37323722

37333723
uint256 const badContextHash{1};
37343724
Buffer const bulletproof = mptAlice.getBulletproof(
@@ -3752,8 +3742,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
37523742
// Test 4: Correct proof to verify the test setup is valid.
37533743
// All parameters are correct, so the transaction should succeed.
37543744
{
3755-
uint256 const contextHash =
3756-
getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
3745+
uint256 const contextHash = getConvertBackContextHash(bob, mptAlice.issuanceID(), env.seq(bob), version);
37573746

37583747
Buffer const proof = mptAlice.getConvertBackProof(
37593748
bob,

src/test/jtx/impl/mpt.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,7 +1057,7 @@ MPTTester::convert(MPTConvert const& arg)
10571057
// if fillSchnorrProof is explicitly set, follow its value;
10581058
// otherwise, default to generating the proof only if holder pub key is
10591059
// present.
1060-
auto const contextHash = getConvertContextHash(arg.account->id(), env_.seq(*arg.account), *id_, *arg.amt);
1060+
auto const contextHash = getConvertContextHash(arg.account->id(), *id_, env_.seq(*arg.account));
10611061

10621062
auto const proof = getSchnorrProof(*arg.account, contextHash);
10631063
if (proof)
@@ -1257,7 +1257,7 @@ MPTTester::send(MPTConfidentialSend const& arg)
12571257
{
12581258
auto const version = getMPTokenVersion(*arg.account);
12591259
auto const ctxHash =
1260-
getSendContextHash(arg.account->id(), env_.seq(*arg.account), *id_, arg.dest->id(), version);
1260+
getSendContextHash(arg.account->id(), *id_, env_.seq(*arg.account), arg.dest->id(), version);
12611261

12621262
auto const nRecipients = getConfidentialRecipientCount(auditorAmt.has_value());
12631263
std::vector<ConfidentialRecipient> recipients;
@@ -1427,7 +1427,7 @@ MPTTester::confidentialClaw(MPTConfidentialClawback const& arg)
14271427
else
14281428
{
14291429
std::uint32_t const seq = env_.seq(account);
1430-
uint256 const contextHash = getClawbackContextHash(account.id(), seq, *id_, *arg.amt, arg.holder->id());
1430+
uint256 const contextHash = getClawbackContextHash(account.id(), *id_, seq, arg.holder->id());
14311431

14321432
auto const privKey = getPrivKey(account);
14331433
if (!privKey || privKey->size() != ecPrivKeyLength)
@@ -1707,8 +1707,7 @@ MPTTester::convertBack(MPTConvertBack const& arg)
17071707

17081708
// if the caller generated ciphertexts themselves, they should also
17091709
// generate the proof themselves from the blinding factor
1710-
uint256 const contextHash =
1711-
getConvertBackContextHash(arg.account->id(), env_.seq(*arg.account), *id_, *arg.amt, version);
1710+
uint256 const contextHash = getConvertBackContextHash(arg.account->id(), *id_, env_.seq(*arg.account), version);
17121711
auto const prevEncryptedSpendingBalance = getEncryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING);
17131712

17141713
Buffer proof;

src/xrpld/app/tx/detail/ConfidentialMPTClawback.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ ConfidentialMPTClawback::preclaim(PreclaimContext const& ctx)
8383
if (amount > (*sleIssuance)[~sfConfidentialOutstandingAmount].value_or(0))
8484
return tecINSUFFICIENT_FUNDS;
8585

86-
auto const contextHash = getClawbackContextHash(account, ctx.tx[sfSequence], mptIssuanceID, amount, holder);
86+
auto const contextHash = getClawbackContextHash(account, mptIssuanceID, ctx.tx.getSeqProxy().value(), holder);
8787

8888
// Verify the revealed confidential amount by the issuer matches the exact
8989
// confidential balance of the holder.

src/xrpld/app/tx/detail/ConfidentialMPTConvert.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ ConfidentialMPTConvert::preclaim(PreclaimContext const& ctx)
120120
{
121121
holderPubKey = ctx.tx[sfHolderElGamalPublicKey];
122122

123-
auto const contextHash = getConvertContextHash(account, ctx.tx[sfSequence], issuanceID, amount);
123+
auto const contextHash = getConvertContextHash(account, issuanceID, ctx.tx.getSeqProxy().value());
124124

125125
// when register new pk, verify through schnorr proof
126126
if (!isTesSuccess(verifySchnorrProof(holderPubKey, ctx.tx[sfZKProof], contextHash)))

src/xrpld/app/tx/detail/ConfidentialMPTConvertBack.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ verifyProofs(STTx const& tx, std::shared_ptr<SLE const> const& issuance, std::sh
6969
auto const holderPubKey = (*mptoken)[sfHolderElGamalPublicKey];
7070

7171
auto const contextHash = getConvertBackContextHash(
72-
account, tx[sfSequence], mptIssuanceID, amount, (*mptoken)[~sfConfidentialBalanceVersion].value_or(0));
72+
account, mptIssuanceID, tx.getSeqProxy().value(), (*mptoken)[~sfConfidentialBalanceVersion].value_or(0));
7373

7474
// Prepare Auditor Info
7575
std::optional<ConfidentialRecipient> auditor;

src/xrpld/app/tx/detail/ConfidentialMPTSend.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ verifySendProofs(
132132
// Prepare the context hash
133133
auto const contextHash = getSendContextHash(
134134
ctx.tx[sfAccount],
135-
ctx.tx[sfSequence],
136135
ctx.tx[sfMPTokenIssuanceID],
136+
ctx.tx.getSeqProxy().value(),
137137
ctx.tx[sfDestination],
138138
(*sleSenderMPToken)[~sfConfidentialBalanceVersion].value_or(0));
139139

0 commit comments

Comments
 (0)