mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-06 18:26:51 +00:00
update sfBlindingFactor to type uint256 and refactor helper functions to return std::optional
This commit is contained in:
@@ -371,7 +371,7 @@ verifyMultiCiphertextEqualityProof(
|
||||
if (recipients.size() != nRecipients)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (proof.size() != secp256k1_mpt_proof_equality_shared_r_size(nRecipients))
|
||||
if (proof.size() != getEqualityProofSize(nRecipients))
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
auto const ctx = secp256k1Context();
|
||||
@@ -700,12 +700,12 @@ verifyAggregatedBulletproof(
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
computeSendRemainder(Slice const& balanceCommitment, Slice const& amountCommitment, Buffer& out)
|
||||
std::optional<Buffer>
|
||||
computeSendRemainder(Slice const& balanceCommitment, Slice const& amountCommitment)
|
||||
{
|
||||
if (balanceCommitment.size() != ecPedersenCommitmentLength ||
|
||||
amountCommitment.size() != ecPedersenCommitmentLength)
|
||||
return tecINTERNAL;
|
||||
return std::nullopt;
|
||||
|
||||
auto const ctx = secp256k1Context();
|
||||
|
||||
@@ -714,7 +714,7 @@ computeSendRemainder(Slice const& balanceCommitment, Slice const& amountCommitme
|
||||
ctx, &pcBalance, balanceCommitment.data(), ecPedersenCommitmentLength);
|
||||
res != 1)
|
||||
{
|
||||
return tecINTERNAL;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
secp256k1_pubkey pcAmount;
|
||||
@@ -722,13 +722,13 @@ computeSendRemainder(Slice const& balanceCommitment, Slice const& amountCommitme
|
||||
ctx, &pcAmount, amountCommitment.data(), ecPedersenCommitmentLength);
|
||||
res != 1)
|
||||
{
|
||||
return tecINTERNAL;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Negate PC_amount point to get -PC_amount
|
||||
if (auto res = secp256k1_ec_pubkey_negate(ctx, &pcAmount); res != 1)
|
||||
{
|
||||
return tecINTERNAL;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Compute pcRem = pcBalance + (-pcAmount)
|
||||
@@ -736,27 +736,28 @@ computeSendRemainder(Slice const& balanceCommitment, Slice const& amountCommitme
|
||||
secp256k1_pubkey pcRem;
|
||||
if (auto res = secp256k1_ec_pubkey_combine(ctx, &pcRem, summands, 2); res != 1)
|
||||
{
|
||||
return tecINTERNAL;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Serialize result to compressed format
|
||||
Buffer out;
|
||||
out.alloc(ecPedersenCommitmentLength);
|
||||
size_t outLen = ecPedersenCommitmentLength;
|
||||
if (auto res = secp256k1_ec_pubkey_serialize(
|
||||
ctx, out.data(), &outLen, &pcRem, SECP256K1_EC_COMPRESSED);
|
||||
res != 1)
|
||||
res != 1 || outLen != ecPedersenCommitmentLength)
|
||||
{
|
||||
return tecINTERNAL;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
return out;
|
||||
}
|
||||
|
||||
TER
|
||||
computeConvertBackRemainder(Slice const& commitment, uint64_t amount, Buffer& out)
|
||||
std::optional<Buffer>
|
||||
computeConvertBackRemainder(Slice const& commitment, uint64_t amount)
|
||||
{
|
||||
if (commitment.size() != ecPedersenCommitmentLength || amount == 0)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
return std::nullopt; // LCOV_EXCL_LINE
|
||||
|
||||
auto const ctx = secp256k1Context();
|
||||
|
||||
@@ -766,7 +767,7 @@ computeConvertBackRemainder(Slice const& commitment, uint64_t amount, Buffer& ou
|
||||
ctx, &pcBalance, commitment.data(), ecPedersenCommitmentLength);
|
||||
res != 1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
return std::nullopt; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// Convert amount to 32-byte big-endian scalar
|
||||
@@ -778,13 +779,13 @@ computeConvertBackRemainder(Slice const& commitment, uint64_t amount, Buffer& ou
|
||||
secp256k1_pubkey mG;
|
||||
if (auto res = secp256k1_ec_pubkey_create(ctx, &mG, mScalar); res != 1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
return std::nullopt; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// Negate mG to get -mG
|
||||
if (auto res = secp256k1_ec_pubkey_negate(ctx, &mG); res != 1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
return std::nullopt; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// Compute pcRem = pcBalance + (-mG)
|
||||
@@ -792,19 +793,20 @@ computeConvertBackRemainder(Slice const& commitment, uint64_t amount, Buffer& ou
|
||||
secp256k1_pubkey pcRem;
|
||||
if (auto res = secp256k1_ec_pubkey_combine(ctx, &pcRem, summands, 2); res != 1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
return std::nullopt; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// Serialize result to compressed format
|
||||
Buffer out;
|
||||
out.alloc(ecPedersenCommitmentLength);
|
||||
size_t outLen = ecPedersenCommitmentLength;
|
||||
if (auto res = secp256k1_ec_pubkey_serialize(
|
||||
ctx, out.data(), &outLen, &pcRem, SECP256K1_EC_COMPRESSED);
|
||||
res != 1 || outLen != ecPedersenCommitmentLength)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
return std::nullopt; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
return out;
|
||||
}
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -56,7 +56,7 @@ ConfidentialMPTClawback::preclaim(PreclaimContext const& ctx)
|
||||
if (!sleIssuance)
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
|
||||
// Sanity check: issuer must be the same as account
|
||||
// Sanity check: account must be the same as issuer
|
||||
if (sleIssuance->getAccountID(sfIssuer) != account)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
@@ -123,7 +123,7 @@ ConfidentialMPTClawback::doApply()
|
||||
|
||||
// Set holder's confidential balances to encrypted zero
|
||||
(*sleHolderMPToken)[sfConfidentialBalanceInbox] = *encZeroForHolder;
|
||||
(*sleHolderMPToken)[sfConfidentialBalanceSpending] = *encZeroForHolder;
|
||||
(*sleHolderMPToken)[sfConfidentialBalanceSpending] = std::move(*encZeroForHolder);
|
||||
(*sleHolderMPToken)[sfIssuerEncryptedBalance] = std::move(*encZeroForIssuer);
|
||||
incrementConfidentialVersion(*sleHolderMPToken);
|
||||
|
||||
|
||||
@@ -22,9 +22,6 @@ ConfidentialMPTConvert::preflight(PreflightContext const& ctx)
|
||||
if (ctx.tx[sfMPTAmount] > maxMPTokenAmount)
|
||||
return temBAD_AMOUNT;
|
||||
|
||||
if (ctx.tx[sfBlindingFactor].size() != ecBlindingFactorLength)
|
||||
return temMALFORMED;
|
||||
|
||||
if (ctx.tx.isFieldPresent(sfHolderEncryptionKey))
|
||||
{
|
||||
if (!isValidCompressedECPoint(ctx.tx[sfHolderEncryptionKey]))
|
||||
@@ -35,13 +32,14 @@ ConfidentialMPTConvert::preflight(PreflightContext const& ctx)
|
||||
if (!ctx.tx.isFieldPresent(sfZKProof))
|
||||
return temMALFORMED;
|
||||
|
||||
// verify schnorr proof length when registerring holder ec public key
|
||||
// verify schnorr proof length when registering holder ec public key
|
||||
if (ctx.tx[sfZKProof].size() != ecSchnorrProofLength)
|
||||
return temMALFORMED;
|
||||
}
|
||||
else
|
||||
{
|
||||
// zkp should not be present if public key was already set
|
||||
// Either both sfHolderEncryptionKey and sfZKProof should be present, or both should be
|
||||
// absent.
|
||||
if (ctx.tx.isFieldPresent(sfZKProof))
|
||||
return temMALFORMED;
|
||||
}
|
||||
@@ -66,7 +64,8 @@ ConfidentialMPTConvert::preclaim(PreclaimContext const& ctx)
|
||||
if (!sleIssuance)
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
|
||||
if (!sleIssuance->isFlag(lsfMPTCanConfidentialAmount))
|
||||
if (!sleIssuance->isFlag(lsfMPTCanConfidentialAmount) ||
|
||||
!sleIssuance->isFieldPresent(sfIssuerEncryptionKey))
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// already checked in preflight, but should also check that issuer on the
|
||||
@@ -74,10 +73,6 @@ ConfidentialMPTConvert::preclaim(PreclaimContext const& ctx)
|
||||
if (sleIssuance->getAccountID(sfIssuer) == account)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
// issuer has not uploaded their pub key yet
|
||||
if (!sleIssuance->isFieldPresent(sfIssuerEncryptionKey))
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
bool const hasAuditor = ctx.tx.isFieldPresent(sfAuditorEncryptedAmount);
|
||||
bool const requiresAuditor = sleIssuance->isFieldPresent(sfAuditorEncryptionKey);
|
||||
|
||||
@@ -142,9 +137,10 @@ ConfidentialMPTConvert::preclaim(PreclaimContext const& ctx)
|
||||
(*sleIssuance)[sfAuditorEncryptionKey], ctx.tx[sfAuditorEncryptedAmount]});
|
||||
}
|
||||
|
||||
auto const blindingFactor = ctx.tx[sfBlindingFactor];
|
||||
return verifyRevealedAmount(
|
||||
amount,
|
||||
ctx.tx[sfBlindingFactor],
|
||||
Slice(blindingFactor.data(), blindingFactor.size()),
|
||||
{holderPubKey, ctx.tx[sfHolderEncryptedAmount]},
|
||||
{(*sleIssuance)[sfIssuerEncryptionKey], ctx.tx[sfIssuerEncryptedAmount]},
|
||||
auditor);
|
||||
|
||||
@@ -24,9 +24,6 @@ ConfidentialMPTConvertBack::preflight(PreflightContext const& ctx)
|
||||
if (ctx.tx[sfMPTAmount] == 0 || ctx.tx[sfMPTAmount] > maxMPTokenAmount)
|
||||
return temBAD_AMOUNT;
|
||||
|
||||
if (ctx.tx[sfBlindingFactor].size() != ecBlindingFactorLength)
|
||||
return temMALFORMED;
|
||||
|
||||
if (!isValidCompressedECPoint(ctx.tx[sfBalanceCommitment]))
|
||||
return temMALFORMED;
|
||||
|
||||
@@ -93,7 +90,7 @@ verifyProofs(
|
||||
// verify revealed amount
|
||||
if (auto const ter = verifyRevealedAmount(
|
||||
amount,
|
||||
blindingFactor,
|
||||
Slice(blindingFactor.data(), blindingFactor.size()),
|
||||
{holderPubKey, tx[sfHolderEncryptedAmount]},
|
||||
{(*issuance)[sfIssuerEncryptionKey], tx[sfIssuerEncryptedAmount]},
|
||||
auditor);
|
||||
@@ -141,18 +138,18 @@ verifyProofs(
|
||||
// verify bullet proof
|
||||
{
|
||||
// Compute PC_rem = PC_balance - mG (the commitment to the remaining balance)
|
||||
Buffer pcRem;
|
||||
if (auto const ter = computeConvertBackRemainder(tx[sfBalanceCommitment], amount, pcRem);
|
||||
!isTesSuccess(ter))
|
||||
if (auto pcRem = computeConvertBackRemainder(tx[sfBalanceCommitment], amount))
|
||||
{
|
||||
valid = false;
|
||||
// The bulletproof verifies that the remaining balance is non-negative
|
||||
std::vector<Slice> commitments{Slice(pcRem->data(), pcRem->size())};
|
||||
|
||||
if (auto const ter = verifyAggregatedBulletproof(bulletproof, commitments, contextHash);
|
||||
!isTesSuccess(ter))
|
||||
{
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
// The bulletproof verifies that the remaining balance is non-negative
|
||||
std::vector<Slice> commitments{Slice(pcRem.data(), pcRem.size())};
|
||||
|
||||
if (auto const ter = verifyAggregatedBulletproof(bulletproof, commitments, contextHash);
|
||||
!isTesSuccess(ter))
|
||||
else
|
||||
{
|
||||
valid = false;
|
||||
}
|
||||
|
||||
@@ -40,11 +40,10 @@ ConfidentialMPTSend::preflight(PreflightContext const& ctx)
|
||||
|
||||
// Check the length of the ZKProof
|
||||
auto const recipientCount = getConfidentialRecipientCount(hasAuditor);
|
||||
auto const sizeEquality = secp256k1_mpt_proof_equality_shared_r_size(recipientCount);
|
||||
auto const sizePedersenLinkage = 2 * ecPedersenProofLength;
|
||||
auto const sizeEquality = getEqualityProofSize(recipientCount);
|
||||
|
||||
if (ctx.tx[sfZKProof].length() !=
|
||||
sizeEquality + sizePedersenLinkage + ecDoubleBulletproofLength)
|
||||
sizeEquality + doublePedersenProofLength + ecDoubleBulletproofLength)
|
||||
return temMALFORMED;
|
||||
|
||||
// Check the Pedersen commitments are valid
|
||||
@@ -86,7 +85,7 @@ verifySendProofs(
|
||||
size_t currentOffset = 0;
|
||||
|
||||
// Extract equality proof
|
||||
auto const sizeEquality = secp256k1_mpt_proof_equality_shared_r_size(recipientCount);
|
||||
auto const sizeEquality = getEqualityProofSize(recipientCount);
|
||||
if (remainingLength < sizeEquality)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
@@ -183,22 +182,15 @@ verifySendProofs(
|
||||
|
||||
// Verify Range Proof
|
||||
{
|
||||
Buffer pcRem;
|
||||
|
||||
// Derive PC_rem = PC_balance - PC_amount
|
||||
if (auto const ter = computeSendRemainder(
|
||||
ctx.tx[sfBalanceCommitment], ctx.tx[sfAmountCommitment], pcRem);
|
||||
!isTesSuccess(ter))
|
||||
{
|
||||
valid = false;
|
||||
}
|
||||
else
|
||||
if (auto pcRem =
|
||||
computeSendRemainder(ctx.tx[sfBalanceCommitment], ctx.tx[sfAmountCommitment]))
|
||||
{
|
||||
// Aggregated commitments: [PC_amount, PC_rem]
|
||||
// Prove that both the transfer amount and the remaining balance are in range
|
||||
std::vector<Slice> commitments;
|
||||
commitments.push_back(ctx.tx[sfAmountCommitment]);
|
||||
commitments.push_back(Slice{pcRem.data(), pcRem.size()});
|
||||
commitments.push_back(Slice{pcRem->data(), pcRem->size()});
|
||||
|
||||
if (auto const ter = verifyAggregatedBulletproof(rangeProof, commitments, contextHash);
|
||||
!isTesSuccess(ter))
|
||||
@@ -206,6 +198,10 @@ verifySendProofs(
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid)
|
||||
@@ -271,11 +267,6 @@ ConfidentialMPTSend::preclaim(PreclaimContext const& ctx)
|
||||
!sleSenderMPToken->isFieldPresent(sfIssuerEncryptedBalance))
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// Sanity check: MPToken's auditor field must be present if auditing is
|
||||
// enabled
|
||||
if (requiresAuditor && !sleSenderMPToken->isFieldPresent(sfAuditorEncryptedBalance))
|
||||
return tefINTERNAL;
|
||||
|
||||
// Check destination's MPToken existence
|
||||
auto const sleDestinationMPToken = ctx.view.read(keylet::mptoken(mptIssuanceID, destination));
|
||||
if (!sleDestinationMPToken)
|
||||
@@ -287,6 +278,13 @@ ConfidentialMPTSend::preclaim(PreclaimContext const& ctx)
|
||||
!sleDestinationMPToken->isFieldPresent(sfIssuerEncryptedBalance))
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// Sanity check: Both MPTokens' auditor fields must be present if auditing
|
||||
// is enabled
|
||||
if (requiresAuditor &&
|
||||
(!sleSenderMPToken->isFieldPresent(sfAuditorEncryptedBalance) ||
|
||||
!sleDestinationMPToken->isFieldPresent(sfAuditorEncryptedBalance)))
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
// Check lock
|
||||
MPTIssue const mptIssue(mptIssuanceID);
|
||||
if (auto const ter = checkFrozen(ctx.view, account, mptIssue); !isTesSuccess(ter))
|
||||
|
||||
@@ -71,7 +71,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
|
||||
std::string
|
||||
getTrivialSendProofHex(size_t nRecipients)
|
||||
{
|
||||
size_t const sizeEquality = secp256k1_mpt_proof_equality_shared_r_size(nRecipients);
|
||||
size_t const sizeEquality = getEqualityProofSize(nRecipients);
|
||||
size_t const totalSize =
|
||||
sizeEquality + (2 * ecPedersenProofLength) + ecDoubleBulletproofLength;
|
||||
|
||||
@@ -365,15 +365,6 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
|
||||
.err = temMALFORMED,
|
||||
});
|
||||
|
||||
// blinding factor length is invalid
|
||||
mptAlice.convert({
|
||||
.account = alice,
|
||||
.amt = 10,
|
||||
.holderPubKey = mptAlice.getPubKey(bob),
|
||||
.blindingFactor = makeZeroBuffer(10),
|
||||
.err = temMALFORMED,
|
||||
});
|
||||
|
||||
// Holder encrypted amount is empty (length 0)
|
||||
mptAlice.convert({
|
||||
.account = bob,
|
||||
@@ -2952,14 +2943,6 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
|
||||
.err = temBAD_AMOUNT,
|
||||
});
|
||||
|
||||
// invalid blinding factor length
|
||||
mptAlice.convertBack({
|
||||
.account = alice,
|
||||
.amt = 30,
|
||||
.blindingFactor = Buffer{},
|
||||
.err = temMALFORMED,
|
||||
});
|
||||
|
||||
// Balance commitment has correct length but invalid EC point data
|
||||
mptAlice.convertBack({
|
||||
.account = bob,
|
||||
|
||||
@@ -827,7 +827,7 @@ MPTTester::getConfidentialSendProof(
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
size_t const sizeEquality = secp256k1_mpt_proof_equality_shared_r_size(nRecipients);
|
||||
size_t const sizeEquality = getEqualityProofSize(nRecipients);
|
||||
Buffer equalityProof(sizeEquality);
|
||||
|
||||
if (secp256k1_mpt_prove_equality_shared_r(
|
||||
|
||||
Reference in New Issue
Block a user