Add ciphertext check (#5930)

This commit is contained in:
Shawn Xie
2025-10-23 11:57:18 -04:00
committed by GitHub
parent 8e9cb3c1da
commit 35e4fad557
6 changed files with 53 additions and 6 deletions

View File

@@ -130,6 +130,14 @@ serializeEcPair(
secp256k1_pubkey const& in2,
Buffer& buffer);
/**
* @brief Verifies that a buffer contains two valid, parsable EC public keys.
* @param buffer The input buffer containing two concatenated components.
* @return true if both components can be parsed successfully, false otherwise.
*/
bool
isValidCiphertext(Slice const& buffer);
TER
homomorphicAdd(Slice const& a, Slice const& b, Buffer& out);

View File

@@ -141,6 +141,7 @@ enum TEMcodes : TERUnderlyingType {
temARRAY_TOO_LARGE,
temBAD_TRANSFER_FEE,
temINVALID_INNER_BATCH,
temBAD_CIPHERTEXT,
};
//------------------------------------------------------------------------------

View File

@@ -371,6 +371,18 @@ serializeEcPair(
return res1 && res2;
}
bool
isValidCiphertext(Slice const& buffer)
{
// Local/temporary variables to pass to makeEcPair.
// Their contents will be discarded when the function returns.
secp256k1_pubkey key1;
secp256k1_pubkey key2;
// Call makeEcPair and return its result.
return makeEcPair(buffer, key1, key2);
}
TER
homomorphicAdd(Slice const& a, Slice const& b, Buffer& out)
{
@@ -516,12 +528,6 @@ encryptCanonicalZeroAmount(
// Allocate ciphertext placeholders
secp256k1_pubkey c1, c2;
// Prepare a random blinding factor
unsigned char blinding_factor[32];
if (RAND_bytes(blinding_factor, 32) != 1)
Throw<std::runtime_error>("Failed to generate random number");
secp256k1_pubkey pubKey;
std::memcpy(pubKey.data, pubKeySlice.data(), ecPubKeyLength);

View File

@@ -221,6 +221,7 @@ transResults()
MAKE_ERROR(temARRAY_TOO_LARGE, "Malformed: Array is too large."),
MAKE_ERROR(temBAD_TRANSFER_FEE, "Malformed: Transfer fee is outside valid range."),
MAKE_ERROR(temINVALID_INNER_BATCH, "Malformed: Invalid inner batch transaction."),
MAKE_ERROR(temBAD_CIPHERTEXT, "Malformed: Invalid ciphertext."),
MAKE_ERROR(terRETRY, "Retry transaction."),
MAKE_ERROR(terFUNDS_SPENT, "DEPRECATED."),

View File

@@ -153,6 +153,33 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
.holderPubKey = mptAlice.getPubKey(bob),
.err = temMALFORMED});
// A 66-byte array of random unsigned char values
unsigned char badCiphertext[ecGamalEncryptedTotalLength] = {
0x3E, 0x9A, 0x0F, 0x7C, 0x51, 0xD8, 0x22, 0x8B, 0x6E, 0x14, 0xC9,
0xF5, 0x4D, 0x6A, 0x03, 0x81, 0x77, 0x2B, 0xEE, 0x9F, 0x10, 0xC2,
0x57, 0x3D, 0x88, 0x65, 0x0C, 0xAB, 0xF1, 0x4E, 0x19, 0x96, 0x2A,
0x73, 0xDC, 0x44, 0xB8, 0x5F, 0x01, 0xEA, 0x87, 0x36, 0x60, 0xCE,
0x92, 0x25, 0x7D, 0x5B, 0xC0, 0x1E, 0x48, 0xF9, 0x84, 0x33, 0x67,
0xAD, 0x0B, 0xE3, 0x91, 0x50, 0xDA, 0x2F, 0x75, 0xC6, 0xBD, 0x42};
mptAlice.convert(
{.account = bob,
.amt = 1,
.proof = "123",
.holderPubKey = mptAlice.getPubKey(bob),
.holderEncryptedAmt =
Buffer{badCiphertext, ecGamalEncryptedTotalLength},
.err = temBAD_CIPHERTEXT});
mptAlice.convert(
{.account = bob,
.amt = 1,
.proof = "123",
.holderPubKey = mptAlice.getPubKey(bob),
.issuerEncryptedAmt =
Buffer{badCiphertext, ecGamalEncryptedTotalLength},
.err = temBAD_CIPHERTEXT});
// todo: change to to check proof size
// mptAlice.convert(
// {.account = bob,

View File

@@ -47,6 +47,10 @@ ConfidentialConvert::preflight(PreflightContext const& ctx)
if (ctx.tx[sfMPTAmount] > maxMPTokenAmount)
return temMALFORMED;
if (!isValidCiphertext(ctx.tx[sfHolderEncryptedAmount]) ||
!isValidCiphertext(ctx.tx[sfIssuerEncryptedAmount]))
return temBAD_CIPHERTEXT;
// if (ctx.tx[sfZKProof].length() != ecEqualityProofLength)
// return temMALFORMED;