mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-29 15:37:57 +00:00
Update hashing and support ticket (#6444)
This commit is contained in:
@@ -50,15 +50,15 @@ incrementConfidentialVersion(STObject& mptoken)
|
||||
/**
|
||||
* @brief Adds common fields to a serializer for ZKP context hash generation.
|
||||
*
|
||||
* Serializes the transaction type, account, sequence number, and issuance ID
|
||||
* Serializes the transaction type, account, issuance ID and sequence/ticket number
|
||||
* into the provided serializer. These fields form the base of all context
|
||||
* hashes used in zero-knowledge proofs.
|
||||
*
|
||||
* @param s The serializer to append fields to.
|
||||
* @param txType The transaction type identifier.
|
||||
* @param account The account ID of the transaction sender.
|
||||
* @param sequence The transaction sequence number.
|
||||
* @param issuanceID The MPToken Issuance ID.
|
||||
* @param sequence The transaction sequence number or ticket number.
|
||||
*/
|
||||
void
|
||||
addCommonZKPFields(
|
||||
@@ -75,8 +75,8 @@ addCommonZKPFields(
|
||||
* this specific send transaction, preventing proof reuse across transactions.
|
||||
*
|
||||
* @param account The sender's account ID.
|
||||
* @param sequence The transaction sequence number.
|
||||
* @param issuanceID The MPToken Issuance ID.
|
||||
* @param sequence The transaction sequence number or ticket number.
|
||||
* @param destination The destination account ID.
|
||||
* @param version The sender's confidential balance version.
|
||||
* @return A 256-bit context hash unique to this transaction.
|
||||
@@ -84,8 +84,8 @@ addCommonZKPFields(
|
||||
uint256
|
||||
getSendContextHash(
|
||||
AccountID const& account,
|
||||
std::uint32_t sequence,
|
||||
uint192 const& issuanceID,
|
||||
std::uint32_t sequence,
|
||||
AccountID const& destination,
|
||||
std::uint32_t version);
|
||||
|
||||
@@ -96,18 +96,16 @@ getSendContextHash(
|
||||
* specific clawback transaction.
|
||||
*
|
||||
* @param account The issuer's account ID.
|
||||
* @param sequence The transaction sequence number.
|
||||
* @param issuanceID The MPToken Issuance ID.
|
||||
* @param amount The amount being clawed back.
|
||||
* @param sequence The transaction sequence number or ticket number.
|
||||
* @param holder The holder's account ID being clawed back from.
|
||||
* @return A 256-bit context hash unique to this transaction.
|
||||
*/
|
||||
uint256
|
||||
getClawbackContextHash(
|
||||
AccountID const& account,
|
||||
std::uint32_t sequence,
|
||||
uint192 const& issuanceID,
|
||||
std::uint64_t amount,
|
||||
std::uint32_t sequence,
|
||||
AccountID const& holder);
|
||||
|
||||
/**
|
||||
@@ -117,17 +115,12 @@ getClawbackContextHash(
|
||||
* registration) to this specific convert transaction.
|
||||
*
|
||||
* @param account The holder's account ID.
|
||||
* @param sequence The transaction sequence number.
|
||||
* @param issuanceID The MPToken Issuance ID.
|
||||
* @param amount The amount being converted to confidential.
|
||||
* @param sequence The transaction sequence number or a ticket number.
|
||||
* @return A 256-bit context hash unique to this transaction.
|
||||
*/
|
||||
uint256
|
||||
getConvertContextHash(
|
||||
AccountID const& account,
|
||||
std::uint32_t sequence,
|
||||
uint192 const& issuanceID,
|
||||
std::uint64_t amount);
|
||||
getConvertContextHash(AccountID const& account, uint192 const& issuanceID, std::uint32_t sequence);
|
||||
|
||||
/**
|
||||
* @brief Generates the context hash for ConfidentialMPTConvertBack transactions.
|
||||
@@ -136,18 +129,16 @@ getConvertContextHash(
|
||||
* this specific convert-back transaction.
|
||||
*
|
||||
* @param account The holder's account ID.
|
||||
* @param sequence The transaction sequence number.
|
||||
* @param issuanceID The MPToken Issuance ID.
|
||||
* @param amount The amount being converted back to public.
|
||||
* @param sequence The transaction sequence number or a ticket number.
|
||||
* @param version The holder's confidential balance version.
|
||||
* @return A 256-bit context hash unique to this transaction.
|
||||
*/
|
||||
uint256
|
||||
getConvertBackContextHash(
|
||||
AccountID const& account,
|
||||
std::uint32_t sequence,
|
||||
uint192 const& issuanceID,
|
||||
std::uint64_t amount,
|
||||
std::uint32_t sequence,
|
||||
std::uint32_t version);
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,26 +12,28 @@ addCommonZKPFields(
|
||||
Serializer& s,
|
||||
std::uint16_t txType,
|
||||
AccountID const& account,
|
||||
std::uint32_t sequence,
|
||||
uint192 const& issuanceID)
|
||||
uint192 const& issuanceID,
|
||||
std::uint32_t sequence)
|
||||
{
|
||||
// TxCommonHash = hash(TxType || Account || IssuanceID || SequenceOrTicket)
|
||||
s.add16(txType);
|
||||
s.addBitString(account);
|
||||
s.add32(sequence);
|
||||
s.addBitString(issuanceID);
|
||||
s.add32(sequence);
|
||||
}
|
||||
|
||||
uint256
|
||||
getSendContextHash(
|
||||
AccountID const& account,
|
||||
std::uint32_t sequence,
|
||||
uint192 const& issuanceID,
|
||||
std::uint32_t sequence,
|
||||
AccountID const& destination,
|
||||
std::uint32_t version)
|
||||
{
|
||||
Serializer s;
|
||||
addCommonZKPFields(s, ttCONFIDENTIAL_MPT_SEND, account, sequence, issuanceID);
|
||||
addCommonZKPFields(s, ttCONFIDENTIAL_MPT_SEND, account, issuanceID, sequence);
|
||||
|
||||
// TxSpecific = identity || freshness
|
||||
s.addBitString(destination);
|
||||
s.addInteger(version);
|
||||
|
||||
@@ -41,27 +43,29 @@ getSendContextHash(
|
||||
uint256
|
||||
getClawbackContextHash(
|
||||
AccountID const& account,
|
||||
std::uint32_t sequence,
|
||||
uint192 const& issuanceID,
|
||||
std::uint64_t amount,
|
||||
std::uint32_t sequence,
|
||||
AccountID const& holder)
|
||||
{
|
||||
Serializer s;
|
||||
addCommonZKPFields(s, ttCONFIDENTIAL_MPT_CLAWBACK, account, sequence, issuanceID);
|
||||
addCommonZKPFields(s, ttCONFIDENTIAL_MPT_CLAWBACK, account, issuanceID, sequence);
|
||||
|
||||
s.add64(amount);
|
||||
// TxSpecific = identity || freshness
|
||||
s.addBitString(holder);
|
||||
s.addInteger(0);
|
||||
|
||||
return s.getSHA512Half();
|
||||
}
|
||||
|
||||
uint256
|
||||
getConvertContextHash(AccountID const& account, std::uint32_t sequence, uint192 const& issuanceID, std::uint64_t amount)
|
||||
getConvertContextHash(AccountID const& account, uint192 const& issuanceID, std::uint32_t sequence)
|
||||
{
|
||||
Serializer s;
|
||||
addCommonZKPFields(s, ttCONFIDENTIAL_MPT_CONVERT, account, sequence, issuanceID);
|
||||
addCommonZKPFields(s, ttCONFIDENTIAL_MPT_CONVERT, account, issuanceID, sequence);
|
||||
|
||||
s.add64(amount);
|
||||
// TxSpecific = identity || freshness
|
||||
s.addBitString(account);
|
||||
s.addInteger(0);
|
||||
|
||||
return s.getSHA512Half();
|
||||
}
|
||||
@@ -69,15 +73,15 @@ getConvertContextHash(AccountID const& account, std::uint32_t sequence, uint192
|
||||
uint256
|
||||
getConvertBackContextHash(
|
||||
AccountID const& account,
|
||||
std::uint32_t sequence,
|
||||
uint192 const& issuanceID,
|
||||
std::uint64_t amount,
|
||||
std::uint32_t sequence,
|
||||
std::uint32_t version)
|
||||
{
|
||||
Serializer s;
|
||||
addCommonZKPFields(s, ttCONFIDENTIAL_MPT_CONVERT_BACK, account, sequence, issuanceID);
|
||||
addCommonZKPFields(s, ttCONFIDENTIAL_MPT_CONVERT_BACK, account, issuanceID, sequence);
|
||||
|
||||
s.add64(amount);
|
||||
// TxSpecific = identity || freshness
|
||||
s.addBitString(account);
|
||||
s.addInteger(version);
|
||||
|
||||
return s.getSHA512Half();
|
||||
|
||||
@@ -2068,8 +2068,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
|
||||
Buffer const convertBlindingFactor = generateBlindingFactor();
|
||||
auto const convertHolderCiphertext = mptAlice.encryptAmount(bob, maxMPTokenAmount, convertBlindingFactor);
|
||||
auto const convertIssuerCiphertext = mptAlice.encryptAmount(alice, maxMPTokenAmount, convertBlindingFactor);
|
||||
auto const convertContextHash =
|
||||
getConvertContextHash(bob.id(), env.seq(bob), mptAlice.issuanceID(), maxMPTokenAmount);
|
||||
auto const convertContextHash = getConvertContextHash(bob.id(), mptAlice.issuanceID(), env.seq(bob));
|
||||
auto const schnorrProof = mptAlice.getSchnorrProof(bob, convertContextHash);
|
||||
BEAST_EXPECT(schnorrProof.has_value());
|
||||
|
||||
@@ -2121,7 +2120,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
|
||||
// Generate the proof using known spending balance value
|
||||
auto const version = mptAlice.getMPTokenVersion(bob);
|
||||
uint256 const convertBackContextHash =
|
||||
getConvertBackContextHash(bob.id(), env.seq(bob), mptAlice.issuanceID(), convertBackAmt, version);
|
||||
getConvertBackContextHash(bob.id(), mptAlice.issuanceID(), env.seq(bob), version);
|
||||
|
||||
Buffer const proof = mptAlice.getConvertBackProof(
|
||||
bob,
|
||||
@@ -3408,8 +3407,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
|
||||
// The proof uses PC(1, rho) but the transaction submits PC(balance, rho).
|
||||
// Verification fails because the proof doesn't match the submitted commitment.
|
||||
{
|
||||
uint256 const contextHash =
|
||||
getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
|
||||
uint256 const contextHash = getConvertBackContextHash(bob, mptAlice.issuanceID(), env.seq(bob), version);
|
||||
Buffer const badPedersenCommitment = mptAlice.getPedersenCommitment(1, pcBlindingFactor);
|
||||
Buffer const proof = mptAlice.getConvertBackProof(
|
||||
bob,
|
||||
@@ -3437,8 +3435,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
|
||||
// The pedersen commitment PC = balance*G + rho*H requires the same rho
|
||||
// used in proof generation. Using a different rho breaks the linkage.
|
||||
{
|
||||
uint256 const contextHash =
|
||||
getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
|
||||
uint256 const contextHash = getConvertBackContextHash(bob, mptAlice.issuanceID(), env.seq(bob), version);
|
||||
|
||||
Buffer const proof = mptAlice.getConvertBackProof(
|
||||
bob,
|
||||
@@ -3466,8 +3463,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
|
||||
// The proof claims balance=1 but the encrypted spending balance contains
|
||||
// the actual balance. Verification fails because the values don't match.
|
||||
{
|
||||
uint256 const contextHash =
|
||||
getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
|
||||
uint256 const contextHash = getConvertBackContextHash(bob, mptAlice.issuanceID(), env.seq(bob), version);
|
||||
|
||||
Buffer const proof = mptAlice.getConvertBackProof(
|
||||
bob,
|
||||
@@ -3496,8 +3492,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
|
||||
// different pedersen commitment. Verification fails because the
|
||||
// submitted commitment doesn't match what the proof was generated for.
|
||||
{
|
||||
uint256 const contextHash =
|
||||
getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
|
||||
uint256 const contextHash = getConvertBackContextHash(bob, mptAlice.issuanceID(), env.seq(bob), version);
|
||||
Buffer const badPedersenCommitment = mptAlice.getPedersenCommitment(1, pcBlindingFactor);
|
||||
Buffer const proof = mptAlice.getConvertBackProof(
|
||||
bob,
|
||||
@@ -3526,8 +3521,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
|
||||
// sequence, issuanceID, amount, version). Using a different context hash
|
||||
// makes the proof invalid for this transaction, preventing replay attacks.
|
||||
{
|
||||
uint256 const contextHash =
|
||||
getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
|
||||
uint256 const contextHash = getConvertBackContextHash(bob, mptAlice.issuanceID(), env.seq(bob), version);
|
||||
uint256 const badContextHash{1};
|
||||
Buffer const pedersenProof = mptAlice.getBalanceLinkageProof(
|
||||
bob,
|
||||
@@ -3560,8 +3554,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
|
||||
// Test 6: Correct proof to verify the test setup is valid.
|
||||
// All parameters are correct, so the transaction should succeed.
|
||||
{
|
||||
uint256 const contextHash =
|
||||
getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
|
||||
uint256 const contextHash = getConvertBackContextHash(bob, mptAlice.issuanceID(), env.seq(bob), version);
|
||||
|
||||
Buffer const proof = mptAlice.getConvertBackProof(
|
||||
bob,
|
||||
@@ -3675,8 +3668,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
|
||||
// commitment was created with (balance - amount). The verifier computes
|
||||
// PC_rem = PC - amount*G and checks if the bulletproof matches, which fails.
|
||||
{
|
||||
uint256 const contextHash =
|
||||
getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
|
||||
uint256 const contextHash = getConvertBackContextHash(bob, mptAlice.issuanceID(), env.seq(bob), version);
|
||||
|
||||
Buffer const bulletproof = mptAlice.getBulletproof(
|
||||
{1}, // wrong remaining balance
|
||||
@@ -3701,8 +3693,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
|
||||
// commitment PC = (balance - amount)*G + rho*H. Using a different rho
|
||||
// creates a commitment mismatch and verification fails.
|
||||
{
|
||||
uint256 const contextHash =
|
||||
getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
|
||||
uint256 const contextHash = getConvertBackContextHash(bob, mptAlice.issuanceID(), env.seq(bob), version);
|
||||
|
||||
Buffer const bulletproof = mptAlice.getBulletproof(
|
||||
{*spendingBalance - amt},
|
||||
@@ -3727,8 +3718,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
|
||||
// sequence, issuanceID, amount, version). Using a different context hash
|
||||
// makes the proof invalid for this transaction, preventing replay attacks.
|
||||
{
|
||||
uint256 const contextHash =
|
||||
getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
|
||||
uint256 const contextHash = getConvertBackContextHash(bob, mptAlice.issuanceID(), env.seq(bob), version);
|
||||
|
||||
uint256 const badContextHash{1};
|
||||
Buffer const bulletproof = mptAlice.getBulletproof(
|
||||
@@ -3752,8 +3742,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
|
||||
// Test 4: Correct proof to verify the test setup is valid.
|
||||
// All parameters are correct, so the transaction should succeed.
|
||||
{
|
||||
uint256 const contextHash =
|
||||
getConvertBackContextHash(bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
|
||||
uint256 const contextHash = getConvertBackContextHash(bob, mptAlice.issuanceID(), env.seq(bob), version);
|
||||
|
||||
Buffer const proof = mptAlice.getConvertBackProof(
|
||||
bob,
|
||||
|
||||
@@ -1057,7 +1057,7 @@ MPTTester::convert(MPTConvert const& arg)
|
||||
// if fillSchnorrProof is explicitly set, follow its value;
|
||||
// otherwise, default to generating the proof only if holder pub key is
|
||||
// present.
|
||||
auto const contextHash = getConvertContextHash(arg.account->id(), env_.seq(*arg.account), *id_, *arg.amt);
|
||||
auto const contextHash = getConvertContextHash(arg.account->id(), *id_, env_.seq(*arg.account));
|
||||
|
||||
auto const proof = getSchnorrProof(*arg.account, contextHash);
|
||||
if (proof)
|
||||
@@ -1257,7 +1257,7 @@ MPTTester::send(MPTConfidentialSend const& arg)
|
||||
{
|
||||
auto const version = getMPTokenVersion(*arg.account);
|
||||
auto const ctxHash =
|
||||
getSendContextHash(arg.account->id(), env_.seq(*arg.account), *id_, arg.dest->id(), version);
|
||||
getSendContextHash(arg.account->id(), *id_, env_.seq(*arg.account), arg.dest->id(), version);
|
||||
|
||||
auto const nRecipients = getConfidentialRecipientCount(auditorAmt.has_value());
|
||||
std::vector<ConfidentialRecipient> recipients;
|
||||
@@ -1427,7 +1427,7 @@ MPTTester::confidentialClaw(MPTConfidentialClawback const& arg)
|
||||
else
|
||||
{
|
||||
std::uint32_t const seq = env_.seq(account);
|
||||
uint256 const contextHash = getClawbackContextHash(account.id(), seq, *id_, *arg.amt, arg.holder->id());
|
||||
uint256 const contextHash = getClawbackContextHash(account.id(), *id_, seq, arg.holder->id());
|
||||
|
||||
auto const privKey = getPrivKey(account);
|
||||
if (!privKey || privKey->size() != ecPrivKeyLength)
|
||||
@@ -1707,8 +1707,7 @@ MPTTester::convertBack(MPTConvertBack const& arg)
|
||||
|
||||
// if the caller generated ciphertexts themselves, they should also
|
||||
// generate the proof themselves from the blinding factor
|
||||
uint256 const contextHash =
|
||||
getConvertBackContextHash(arg.account->id(), env_.seq(*arg.account), *id_, *arg.amt, version);
|
||||
uint256 const contextHash = getConvertBackContextHash(arg.account->id(), *id_, env_.seq(*arg.account), version);
|
||||
auto const prevEncryptedSpendingBalance = getEncryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING);
|
||||
|
||||
Buffer proof;
|
||||
|
||||
@@ -83,7 +83,7 @@ ConfidentialMPTClawback::preclaim(PreclaimContext const& ctx)
|
||||
if (amount > (*sleIssuance)[~sfConfidentialOutstandingAmount].value_or(0))
|
||||
return tecINSUFFICIENT_FUNDS;
|
||||
|
||||
auto const contextHash = getClawbackContextHash(account, ctx.tx[sfSequence], mptIssuanceID, amount, holder);
|
||||
auto const contextHash = getClawbackContextHash(account, mptIssuanceID, ctx.tx.getSeqProxy().value(), holder);
|
||||
|
||||
// Verify the revealed confidential amount by the issuer matches the exact
|
||||
// confidential balance of the holder.
|
||||
|
||||
@@ -120,7 +120,7 @@ ConfidentialMPTConvert::preclaim(PreclaimContext const& ctx)
|
||||
{
|
||||
holderPubKey = ctx.tx[sfHolderElGamalPublicKey];
|
||||
|
||||
auto const contextHash = getConvertContextHash(account, ctx.tx[sfSequence], issuanceID, amount);
|
||||
auto const contextHash = getConvertContextHash(account, issuanceID, ctx.tx.getSeqProxy().value());
|
||||
|
||||
// when register new pk, verify through schnorr proof
|
||||
if (!isTesSuccess(verifySchnorrProof(holderPubKey, ctx.tx[sfZKProof], contextHash)))
|
||||
|
||||
@@ -69,7 +69,7 @@ verifyProofs(STTx const& tx, std::shared_ptr<SLE const> const& issuance, std::sh
|
||||
auto const holderPubKey = (*mptoken)[sfHolderElGamalPublicKey];
|
||||
|
||||
auto const contextHash = getConvertBackContextHash(
|
||||
account, tx[sfSequence], mptIssuanceID, amount, (*mptoken)[~sfConfidentialBalanceVersion].value_or(0));
|
||||
account, mptIssuanceID, tx.getSeqProxy().value(), (*mptoken)[~sfConfidentialBalanceVersion].value_or(0));
|
||||
|
||||
// Prepare Auditor Info
|
||||
std::optional<ConfidentialRecipient> auditor;
|
||||
|
||||
@@ -132,8 +132,8 @@ verifySendProofs(
|
||||
// Prepare the context hash
|
||||
auto const contextHash = getSendContextHash(
|
||||
ctx.tx[sfAccount],
|
||||
ctx.tx[sfSequence],
|
||||
ctx.tx[sfMPTokenIssuanceID],
|
||||
ctx.tx.getSeqProxy().value(),
|
||||
ctx.tx[sfDestination],
|
||||
(*sleSenderMPToken)[~sfConfidentialBalanceVersion].value_or(0));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user