mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-24 23:50:22 +00:00
Support shared r for ConfidentialMPTSend equality proof (#6496)
* Support shared r for send equality proof
This commit is contained in:
@@ -329,18 +329,6 @@ getConfidentialRecipientCount(bool hasAuditor)
|
||||
return hasAuditor ? 4 : 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates the size of a multi-ciphertext equality proof.
|
||||
*
|
||||
* The proof size varies based on the number of recipients because each
|
||||
* additional recipient requires additional proof components.
|
||||
*
|
||||
* @param nRecipients The number of recipients in the transfer.
|
||||
* @return The size in bytes of the equality proof.
|
||||
*/
|
||||
std::size_t
|
||||
getMultiCiphertextEqualityProofSize(std::size_t nRecipients);
|
||||
|
||||
/**
|
||||
* @brief Verifies a multi-ciphertext equality proof.
|
||||
*
|
||||
|
||||
@@ -328,15 +328,6 @@ verifyRevealedAmount(
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
getMultiCiphertextEqualityProofSize(std::size_t nRecipients)
|
||||
{
|
||||
// Points (33 bytes): T_m (1) + T_rG (nRecipients) + T_rP (nRecipients) = 1
|
||||
// + 2nRecipients Scalars (32 bytes): s_m (1) + s_r (nRecipients) = 1 +
|
||||
// nRecipients
|
||||
return ((1 + (2 * nRecipients)) * 33) + ((1 + nRecipients) * 32);
|
||||
}
|
||||
|
||||
TER
|
||||
verifyMultiCiphertextEqualityProof(
|
||||
Slice const& proof,
|
||||
@@ -347,31 +338,55 @@ verifyMultiCiphertextEqualityProof(
|
||||
if (recipients.size() != nRecipients)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (proof.size() != getMultiCiphertextEqualityProofSize(nRecipients))
|
||||
if (proof.size() != secp256k1_mpt_proof_equality_shared_r_size(nRecipients))
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
std::vector<secp256k1_pubkey> r(nRecipients);
|
||||
std::vector<secp256k1_pubkey> s(nRecipients);
|
||||
std::vector<secp256k1_pubkey> pk(nRecipients);
|
||||
auto const ctx = secp256k1Context();
|
||||
|
||||
secp256k1_pubkey c1;
|
||||
std::vector<secp256k1_pubkey> c2_vec(nRecipients);
|
||||
std::vector<secp256k1_pubkey> pk_vec(nRecipients);
|
||||
|
||||
for (size_t i = 0; i < nRecipients; ++i)
|
||||
{
|
||||
auto const& recipient = recipients[i];
|
||||
if (recipient.encryptedAmount.size() != ecGamalEncryptedTotalLength)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (!makeEcPair(recipient.encryptedAmount, r[i], s[i]))
|
||||
if (recipient.encryptedAmount.size() != ecGamalEncryptedTotalLength)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (recipient.publicKey.size() != ecPubKeyLength)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (secp256k1_ec_pubkey_parse(secp256k1Context(), &pk[i], recipient.publicKey.data(), ecPubKeyLength) != 1)
|
||||
// Parse Shared C1 from the first recipient only
|
||||
if (i == 0)
|
||||
{
|
||||
if (!secp256k1_ec_pubkey_parse(ctx, &c1, recipient.encryptedAmount.data(), ecGamalEncryptedLength))
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
else
|
||||
{
|
||||
// All C1 bytes must be the same
|
||||
if (std::memcmp(
|
||||
recipient.encryptedAmount.data(), recipients[0].encryptedAmount.data(), ecGamalEncryptedLength) !=
|
||||
0)
|
||||
{
|
||||
return tecBAD_PROOF;
|
||||
}
|
||||
}
|
||||
|
||||
if (secp256k1_ec_pubkey_parse(
|
||||
ctx, &c2_vec[i], recipient.encryptedAmount.data() + ecGamalEncryptedLength, ecGamalEncryptedLength) !=
|
||||
1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
if (secp256k1_ec_pubkey_parse(ctx, &pk_vec[i], recipient.publicKey.data(), ecPubKeyLength) != 1)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
int const result = secp256k1_mpt_verify_same_plaintext_multi(
|
||||
secp256k1Context(), proof.data(), proof.size(), nRecipients, r.data(), s.data(), pk.data(), contextHash.data());
|
||||
int const result = secp256k1_mpt_verify_equality_shared_r(
|
||||
ctx, proof.data(), nRecipients, &c1, c2_vec.data(), pk_vec.data(), contextHash.data());
|
||||
|
||||
if (result != 1)
|
||||
return tecBAD_PROOF;
|
||||
|
||||
@@ -71,7 +71,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
|
||||
std::string
|
||||
getTrivialSendProofHex(size_t nRecipients)
|
||||
{
|
||||
size_t const sizeEquality = getMultiCiphertextEqualityProofSize(nRecipients);
|
||||
size_t const sizeEquality = secp256k1_mpt_proof_equality_shared_r_size(nRecipients);
|
||||
size_t const totalSize = sizeEquality + (2 * ecPedersenProofLength) + ecDoubleBulletproofLength;
|
||||
|
||||
Buffer buf(totalSize);
|
||||
|
||||
@@ -762,9 +762,9 @@ MPTTester::getConfidentialSendProof(
|
||||
|
||||
auto const ctx = secp256k1Context();
|
||||
|
||||
std::vector<secp256k1_pubkey> r(nRecipients);
|
||||
std::vector<secp256k1_pubkey> s(nRecipients);
|
||||
std::vector<secp256k1_pubkey> pk(nRecipients);
|
||||
secp256k1_pubkey c1;
|
||||
std::vector<secp256k1_pubkey> c2_vec(nRecipients);
|
||||
std::vector<secp256k1_pubkey> pk_vec(nRecipients);
|
||||
|
||||
std::vector<unsigned char> sr;
|
||||
sr.reserve(nRecipients * ecBlindingFactorLength);
|
||||
@@ -780,36 +780,31 @@ MPTTester::getConfidentialSendProof(
|
||||
if (recipient.publicKey.size() != ecPubKeyLength)
|
||||
return std::nullopt;
|
||||
|
||||
if (!secp256k1_ec_pubkey_parse(ctx, &r[i], ctData, ecGamalEncryptedLength))
|
||||
if (i == 0)
|
||||
{
|
||||
return std::nullopt;
|
||||
if (!secp256k1_ec_pubkey_parse(ctx, &c1, ctData, ecGamalEncryptedLength))
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!secp256k1_ec_pubkey_parse(ctx, &s[i], ctData + ecGamalEncryptedLength, ecGamalEncryptedLength))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!secp256k1_ec_pubkey_parse(ctx, &pk[i], recipient.publicKey.data(), ecPubKeyLength))
|
||||
if (!secp256k1_ec_pubkey_parse(ctx, &c2_vec[i], ctData + ecGamalEncryptedLength, ecGamalEncryptedLength))
|
||||
return std::nullopt;
|
||||
|
||||
sr.insert(sr.end(), blindingFactor.data(), blindingFactor.data() + ecBlindingFactorLength);
|
||||
if (!secp256k1_ec_pubkey_parse(ctx, &pk_vec[i], recipient.publicKey.data(), ecPubKeyLength))
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
size_t sizeEquality = secp256k1_mpt_prove_same_plaintext_multi_size(nRecipients);
|
||||
size_t const sizeEquality = secp256k1_mpt_proof_equality_shared_r_size(nRecipients);
|
||||
Buffer equalityProof(sizeEquality);
|
||||
|
||||
// Get the multi-ciphertext equality proof
|
||||
if (secp256k1_mpt_prove_same_plaintext_multi(
|
||||
if (secp256k1_mpt_prove_equality_shared_r(
|
||||
ctx,
|
||||
equalityProof.data(),
|
||||
&sizeEquality,
|
||||
amount,
|
||||
blindingFactor.data(), // The shared 'r' witness
|
||||
nRecipients,
|
||||
r.data(),
|
||||
s.data(),
|
||||
pk.data(),
|
||||
sr.data(),
|
||||
&c1,
|
||||
c2_vec.data(),
|
||||
pk_vec.data(),
|
||||
contextHash.data()) != 1)
|
||||
{
|
||||
return std::nullopt;
|
||||
|
||||
@@ -41,7 +41,7 @@ ConfidentialMPTSend::preflight(PreflightContext const& ctx)
|
||||
|
||||
// Check the length of the ZKProof
|
||||
auto const recipientCount = getConfidentialRecipientCount(hasAuditor);
|
||||
auto const sizeEquality = getMultiCiphertextEqualityProofSize(recipientCount);
|
||||
auto const sizeEquality = secp256k1_mpt_proof_equality_shared_r_size(recipientCount);
|
||||
auto const sizePedersenLinkage = 2 * ecPedersenProofLength;
|
||||
|
||||
if (ctx.tx[sfZKProof].length() != sizeEquality + sizePedersenLinkage + ecDoubleBulletproofLength)
|
||||
@@ -81,7 +81,7 @@ verifySendProofs(
|
||||
size_t currentOffset = 0;
|
||||
|
||||
// Extract equality proof
|
||||
auto const sizeEquality = getMultiCiphertextEqualityProofSize(recipientCount);
|
||||
auto const sizeEquality = secp256k1_mpt_proof_equality_shared_r_size(recipientCount);
|
||||
if (remainingLength < sizeEquality)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
|
||||
Reference in New Issue
Block a user