mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-27 00:50:45 +00:00
refactor: return optional buffers for helper functions (#6520)
This commit is contained in:
@@ -25,8 +25,15 @@ namespace xrpl {
|
||||
*/
|
||||
struct ConfidentialRecipient
|
||||
{
|
||||
Slice const publicKey; ///< The recipient's ElGamal public key (64 bytes).
|
||||
Slice const encryptedAmount; ///< The encrypted amount ciphertext (128 bytes).
|
||||
Slice publicKey; ///< The recipient's ElGamal public key (64 bytes).
|
||||
Slice encryptedAmount; ///< The encrypted amount ciphertext (128 bytes).
|
||||
};
|
||||
|
||||
/// Holds two secp256k1 public key components representing an ElGamal ciphertext (C1, C2).
|
||||
struct EcPair
|
||||
{
|
||||
secp256k1_pubkey c1;
|
||||
secp256k1_pubkey c2;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -146,29 +153,25 @@ getConvertBackContextHash(
|
||||
* @brief Parses an ElGamal ciphertext into two secp256k1 public key components.
|
||||
*
|
||||
* Breaks a 66-byte encrypted amount (two 33-byte compressed EC points) into
|
||||
* two secp256k1_pubkey structures (C1, C2) for use in cryptographic operations.
|
||||
* a pair containing (C1, C2) for use in cryptographic operations.
|
||||
*
|
||||
* @param buffer The 66-byte buffer containing the compressed ciphertext.
|
||||
* @param out1 Output: The C1 component of the ElGamal ciphertext.
|
||||
* @param out2 Output: The C2 component of the ElGamal ciphertext.
|
||||
* @return true if parsing succeeds, false if the buffer is invalid.
|
||||
* @return The parsed pair (c1, c2) if successful, std::nullopt if the buffer is invalid.
|
||||
*/
|
||||
bool
|
||||
makeEcPair(Slice const& buffer, secp256k1_pubkey& out1, secp256k1_pubkey& out2);
|
||||
std::optional<EcPair>
|
||||
makeEcPair(Slice const& buffer);
|
||||
|
||||
/**
|
||||
* @brief Serializes two secp256k1 public key components into compressed form.
|
||||
* @brief Serializes an EcPair into compressed form.
|
||||
*
|
||||
* Converts two secp256k1_pubkey structures (C1, C2) back into a 66-byte
|
||||
* buffer containing two 33-byte compressed EC points.
|
||||
* Converts an EcPair (C1, C2) back into a 66-byte buffer containing
|
||||
* two 33-byte compressed EC points.
|
||||
*
|
||||
* @param in1 The C1 component to serialize.
|
||||
* @param in2 The C2 component to serialize.
|
||||
* @param buffer Output: The 66-byte buffer to write the compressed ciphertext.
|
||||
* @return true if serialization succeeds, false otherwise.
|
||||
* @param pair The EcPair to serialize.
|
||||
* @return The 66-byte buffer, or std::nullopt if serialization fails.
|
||||
*/
|
||||
bool
|
||||
serializeEcPair(secp256k1_pubkey const& in1, secp256k1_pubkey const& in2, Buffer& buffer);
|
||||
std::optional<Buffer>
|
||||
serializeEcPair(EcPair const& pair);
|
||||
|
||||
/**
|
||||
* @brief Verifies that a buffer contains two valid, parsable EC public keys.
|
||||
@@ -197,13 +200,12 @@ isValidCompressedECPoint(Slice const& buffer);
|
||||
* Uses the additive homomorphic property of ElGamal encryption to compute
|
||||
* Enc(a + b) from Enc(a) and Enc(b) without decryption.
|
||||
*
|
||||
* @param a The first ciphertext (66 bytes).
|
||||
* @param b The second ciphertext (66 bytes).
|
||||
* @param out Output: The resulting ciphertext Enc(a + b).
|
||||
* @return tesSUCCESS on success, or an error code if parsing fails.
|
||||
* @param a The first ciphertext (66 bytes).
|
||||
* @param b The second ciphertext (66 bytes).
|
||||
* @return The resulting ciphertext Enc(a + b), or std::nullopt on failure.
|
||||
*/
|
||||
TER
|
||||
homomorphicAdd(Slice const& a, Slice const& b, Buffer& out);
|
||||
std::optional<Buffer>
|
||||
homomorphicAdd(Slice const& a, Slice const& b);
|
||||
|
||||
/**
|
||||
* @brief Homomorphically subtracts two ElGamal ciphertexts.
|
||||
@@ -211,13 +213,12 @@ homomorphicAdd(Slice const& a, Slice const& b, Buffer& out);
|
||||
* Uses the additive homomorphic property of ElGamal encryption to compute
|
||||
* Enc(a - b) from Enc(a) and Enc(b) without decryption.
|
||||
*
|
||||
* @param a The minuend ciphertext (66 bytes).
|
||||
* @param b The subtrahend ciphertext (66 bytes).
|
||||
* @param out Output: The resulting ciphertext Enc(a - b).
|
||||
* @return tesSUCCESS on success, or an error code if parsing fails.
|
||||
* @param a The minuend ciphertext (66 bytes).
|
||||
* @param b The subtrahend ciphertext (66 bytes).
|
||||
* @return The resulting ciphertext Enc(a - b), or std::nullopt on failure.
|
||||
*/
|
||||
TER
|
||||
homomorphicSubtract(Slice const& a, Slice const& b, Buffer& out);
|
||||
std::optional<Buffer>
|
||||
homomorphicSubtract(Slice const& a, Slice const& b);
|
||||
|
||||
/**
|
||||
* @brief Encrypts an amount using ElGamal encryption.
|
||||
@@ -275,7 +276,7 @@ verifySchnorrProof(Slice const& pubKeySlice, Slice const& proofSlice, uint256 co
|
||||
*/
|
||||
TER
|
||||
verifyElGamalEncryption(
|
||||
std::uint64_t const amount,
|
||||
uint64_t const amount,
|
||||
Slice const& blindingFactor,
|
||||
Slice const& pubKeySlice,
|
||||
Slice const& ciphertext);
|
||||
@@ -309,7 +310,7 @@ checkEncryptedAmountFormat(STObject const& object);
|
||||
*/
|
||||
TER
|
||||
verifyRevealedAmount(
|
||||
std::uint64_t const amount,
|
||||
uint64_t const amount,
|
||||
Slice const& blindingFactor,
|
||||
ConfidentialRecipient const& holder,
|
||||
ConfidentialRecipient const& issuer,
|
||||
@@ -479,5 +480,5 @@ computeSendRemainder(Slice const& balanceCommitment, Slice const& amountCommitme
|
||||
* @return tesSUCCESS on success, tecINTERNAL on failure or if amount is 0.
|
||||
*/
|
||||
TER
|
||||
computeConvertBackRemainder(Slice const& commitment, std::uint64_t amount, Buffer& out);
|
||||
computeConvertBackRemainder(Slice const& commitment, uint64_t amount, Buffer& out);
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -87,11 +87,11 @@ getConvertBackContextHash(
|
||||
return s.getSHA512Half();
|
||||
}
|
||||
|
||||
bool
|
||||
makeEcPair(Slice const& buffer, secp256k1_pubkey& out1, secp256k1_pubkey& out2)
|
||||
std::optional<EcPair>
|
||||
makeEcPair(Slice const& buffer)
|
||||
{
|
||||
if (buffer.length() != 2 * ecGamalEncryptedLength)
|
||||
return false; // LCOV_EXCL_LINE
|
||||
return std::nullopt; // LCOV_EXCL_LINE
|
||||
|
||||
auto parsePubKey = [](Slice const& slice, secp256k1_pubkey& out) {
|
||||
return secp256k1_ec_pubkey_parse(
|
||||
@@ -104,14 +104,15 @@ makeEcPair(Slice const& buffer, secp256k1_pubkey& out1, secp256k1_pubkey& out2)
|
||||
Slice s1{buffer.data(), ecGamalEncryptedLength};
|
||||
Slice s2{buffer.data() + ecGamalEncryptedLength, ecGamalEncryptedLength};
|
||||
|
||||
int const ret1 = parsePubKey(s1, out1);
|
||||
int const ret2 = parsePubKey(s2, out2);
|
||||
EcPair pair;
|
||||
if (parsePubKey(s1, pair.c1) != 1 || parsePubKey(s2, pair.c2) != 1)
|
||||
return std::nullopt;
|
||||
|
||||
return ret1 == 1 && ret2 == 1;
|
||||
return pair;
|
||||
}
|
||||
|
||||
bool
|
||||
serializeEcPair(secp256k1_pubkey const& in1, secp256k1_pubkey const& in2, Buffer& buffer)
|
||||
std::optional<Buffer>
|
||||
serializeEcPair(EcPair const& pair)
|
||||
{
|
||||
auto serializePubKey = [](secp256k1_pubkey const& pub, unsigned char* out) {
|
||||
size_t outLen = ecGamalEncryptedLength; // 33 bytes
|
||||
@@ -120,19 +121,21 @@ serializeEcPair(secp256k1_pubkey const& in1, secp256k1_pubkey const& in2, Buffer
|
||||
return ret == 1 && outLen == ecGamalEncryptedLength;
|
||||
};
|
||||
|
||||
Buffer buffer(ecGamalEncryptedTotalLength);
|
||||
unsigned char* ptr = buffer.data();
|
||||
bool const res1 = serializePubKey(in1, ptr);
|
||||
bool const res2 = serializePubKey(in2, ptr + ecGamalEncryptedLength);
|
||||
bool const res1 = serializePubKey(pair.c1, ptr);
|
||||
bool const res2 = serializePubKey(pair.c2, ptr + ecGamalEncryptedLength);
|
||||
|
||||
return res1 && res2;
|
||||
if (!res1 || !res2)
|
||||
return std::nullopt;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool
|
||||
isValidCiphertext(Slice const& buffer)
|
||||
{
|
||||
secp256k1_pubkey key1;
|
||||
secp256k1_pubkey key2;
|
||||
return makeEcPair(buffer, key1, key2);
|
||||
return makeEcPair(buffer).has_value();
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -149,57 +152,50 @@ isValidCompressedECPoint(Slice const& buffer)
|
||||
return secp256k1_ec_pubkey_parse(secp256k1Context(), &point, buffer.data(), buffer.size()) == 1;
|
||||
}
|
||||
|
||||
TER
|
||||
homomorphicAdd(Slice const& a, Slice const& b, Buffer& out)
|
||||
std::optional<Buffer>
|
||||
homomorphicAdd(Slice const& a, Slice const& b)
|
||||
{
|
||||
if (a.length() != ecGamalEncryptedTotalLength || b.length() != ecGamalEncryptedTotalLength)
|
||||
return tecINTERNAL;
|
||||
return std::nullopt;
|
||||
|
||||
secp256k1_pubkey aC1;
|
||||
secp256k1_pubkey aC2;
|
||||
secp256k1_pubkey bC1;
|
||||
secp256k1_pubkey bC2;
|
||||
auto const pairA = makeEcPair(a);
|
||||
auto const pairB = makeEcPair(b);
|
||||
|
||||
if (!makeEcPair(a, aC1, aC2) || !makeEcPair(b, bC1, bC2))
|
||||
return tecINTERNAL;
|
||||
if (!pairA || !pairB)
|
||||
return std::nullopt;
|
||||
|
||||
secp256k1_pubkey sumC1;
|
||||
secp256k1_pubkey sumC2;
|
||||
EcPair sum;
|
||||
if (auto res = secp256k1_elgamal_add(
|
||||
secp256k1Context(), &sum.c1, &sum.c2, &pairA->c1, &pairA->c2, &pairB->c1, &pairB->c2);
|
||||
res != 1)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (secp256k1_elgamal_add(secp256k1Context(), &sumC1, &sumC2, &aC1, &aC2, &bC1, &bC2) != 1)
|
||||
return tecINTERNAL;
|
||||
|
||||
if (!serializeEcPair(sumC1, sumC2, out))
|
||||
return tecINTERNAL;
|
||||
|
||||
return tesSUCCESS;
|
||||
return serializeEcPair(sum);
|
||||
}
|
||||
|
||||
TER
|
||||
homomorphicSubtract(Slice const& a, Slice const& b, Buffer& out)
|
||||
std::optional<Buffer>
|
||||
homomorphicSubtract(Slice const& a, Slice const& b)
|
||||
{
|
||||
if (a.length() != ecGamalEncryptedTotalLength || b.length() != ecGamalEncryptedTotalLength)
|
||||
return tecINTERNAL;
|
||||
return std::nullopt;
|
||||
|
||||
secp256k1_pubkey aC1;
|
||||
secp256k1_pubkey aC2;
|
||||
secp256k1_pubkey bC1;
|
||||
secp256k1_pubkey bC2;
|
||||
auto const pairA = makeEcPair(a);
|
||||
auto const pairB = makeEcPair(b);
|
||||
|
||||
if (!makeEcPair(a, aC1, aC2) || !makeEcPair(b, bC1, bC2))
|
||||
return tecINTERNAL;
|
||||
if (!pairA || !pairB)
|
||||
return std::nullopt;
|
||||
|
||||
secp256k1_pubkey diffC1;
|
||||
secp256k1_pubkey diffC2;
|
||||
EcPair diff;
|
||||
if (auto res = secp256k1_elgamal_subtract(
|
||||
secp256k1Context(), &diff.c1, &diff.c2, &pairA->c1, &pairA->c2, &pairB->c1, &pairB->c2);
|
||||
res != 1)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (secp256k1_elgamal_subtract(secp256k1Context(), &diffC1, &diffC2, &aC1, &aC2, &bC1, &bC2) !=
|
||||
1)
|
||||
return tecINTERNAL;
|
||||
|
||||
if (!serializeEcPair(diffC1, diffC2, out))
|
||||
return tecINTERNAL;
|
||||
|
||||
return tesSUCCESS;
|
||||
return serializeEcPair(diff);
|
||||
}
|
||||
|
||||
Buffer
|
||||
@@ -223,20 +219,23 @@ encryptAmount(uint64_t const amt, Slice const& pubKeySlice, Slice const& blindin
|
||||
if (pubKeySlice.size() != ecPubKeyLength)
|
||||
return std::nullopt;
|
||||
|
||||
secp256k1_pubkey c1, c2, pubKey;
|
||||
if (secp256k1_ec_pubkey_parse(
|
||||
secp256k1Context(), &pubKey, pubKeySlice.data(), ecPubKeyLength) != 1)
|
||||
EcPair pair;
|
||||
secp256k1_pubkey pubKey;
|
||||
if (auto res = secp256k1_ec_pubkey_parse(
|
||||
secp256k1Context(), &pubKey, pubKeySlice.data(), ecPubKeyLength);
|
||||
res != 1)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!secp256k1_elgamal_encrypt(
|
||||
secp256k1Context(), &c1, &c2, &pubKey, amt, blindingFactor.data()))
|
||||
if (auto res = secp256k1_elgamal_encrypt(
|
||||
secp256k1Context(), &pair.c1, &pair.c2, &pubKey, amt, blindingFactor.data());
|
||||
res != 1)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
Buffer buf(ecGamalEncryptedTotalLength);
|
||||
if (!serializeEcPair(c1, c2, buf))
|
||||
return std::nullopt;
|
||||
|
||||
return buf;
|
||||
return serializeEcPair(pair);
|
||||
}
|
||||
|
||||
std::optional<Buffer>
|
||||
@@ -245,20 +244,23 @@ encryptCanonicalZeroAmount(Slice const& pubKeySlice, AccountID const& account, M
|
||||
if (pubKeySlice.size() != ecPubKeyLength)
|
||||
return std::nullopt; // LCOV_EXCL_LINE
|
||||
|
||||
secp256k1_pubkey c1, c2, pubKey;
|
||||
if (secp256k1_ec_pubkey_parse(
|
||||
secp256k1Context(), &pubKey, pubKeySlice.data(), ecPubKeyLength) != 1)
|
||||
EcPair pair;
|
||||
secp256k1_pubkey pubKey;
|
||||
if (auto res = secp256k1_ec_pubkey_parse(
|
||||
secp256k1Context(), &pubKey, pubKeySlice.data(), ecPubKeyLength);
|
||||
res != 1)
|
||||
{
|
||||
return std::nullopt; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
if (!generate_canonical_encrypted_zero(
|
||||
secp256k1Context(), &c1, &c2, &pubKey, account.data(), mptId.data()))
|
||||
if (auto res = generate_canonical_encrypted_zero(
|
||||
secp256k1Context(), &pair.c1, &pair.c2, &pubKey, account.data(), mptId.data());
|
||||
res != 1)
|
||||
{
|
||||
return std::nullopt; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
Buffer buf(ecGamalEncryptedTotalLength);
|
||||
if (!serializeEcPair(c1, c2, buf))
|
||||
return std::nullopt; // LCOV_EXCL_LINE
|
||||
|
||||
return buf;
|
||||
return serializeEcPair(pair);
|
||||
}
|
||||
|
||||
TER
|
||||
@@ -271,20 +273,26 @@ verifySchnorrProof(Slice const& pubKeySlice, Slice const& proofSlice, uint256 co
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
secp256k1_pubkey pubKey;
|
||||
if (secp256k1_ec_pubkey_parse(
|
||||
secp256k1Context(), &pubKey, pubKeySlice.data(), ecPubKeyLength) != 1)
|
||||
if (auto res = secp256k1_ec_pubkey_parse(
|
||||
secp256k1Context(), &pubKey, pubKeySlice.data(), ecPubKeyLength);
|
||||
res != 1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
if (secp256k1_mpt_pok_sk_verify(
|
||||
secp256k1Context(), proofSlice.data(), &pubKey, contextHash.data()) != 1)
|
||||
if (auto res = secp256k1_mpt_pok_sk_verify(
|
||||
secp256k1Context(), proofSlice.data(), &pubKey, contextHash.data());
|
||||
res != 1)
|
||||
{
|
||||
return tecBAD_PROOF;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
verifyElGamalEncryption(
|
||||
std::uint64_t const amount,
|
||||
uint64_t const amount,
|
||||
Slice const& blindingFactor,
|
||||
Slice const& pubKeySlice,
|
||||
Slice const& ciphertext)
|
||||
@@ -294,24 +302,30 @@ verifyElGamalEncryption(
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
secp256k1_pubkey pubKey;
|
||||
if (secp256k1_ec_pubkey_parse(
|
||||
secp256k1Context(), &pubKey, pubKeySlice.data(), ecPubKeyLength) != 1)
|
||||
if (auto res = secp256k1_ec_pubkey_parse(
|
||||
secp256k1Context(), &pubKey, pubKeySlice.data(), ecPubKeyLength);
|
||||
res != 1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
auto const pair = makeEcPair(ciphertext);
|
||||
if (!pair)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
secp256k1_pubkey c1, c2;
|
||||
if (!makeEcPair(ciphertext, c1, c2))
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (secp256k1_elgamal_verify_encryption(
|
||||
secp256k1Context(), &c1, &c2, &pubKey, amount, blindingFactor.data()) != 1)
|
||||
if (auto res = secp256k1_elgamal_verify_encryption(
|
||||
secp256k1Context(), &pair->c1, &pair->c2, &pubKey, amount, blindingFactor.data());
|
||||
res != 1)
|
||||
{
|
||||
return tecBAD_PROOF;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
verifyRevealedAmount(
|
||||
std::uint64_t const amount,
|
||||
uint64_t const amount,
|
||||
Slice const& blindingFactor,
|
||||
ConfidentialRecipient const& holder,
|
||||
ConfidentialRecipient const& issuer,
|
||||
@@ -376,9 +390,12 @@ verifyMultiCiphertextEqualityProof(
|
||||
// Parse Shared C1 from the first recipient only
|
||||
if (i == 0)
|
||||
{
|
||||
if (!secp256k1_ec_pubkey_parse(
|
||||
ctx, &c1, recipient.encryptedAmount.data(), ecGamalEncryptedLength))
|
||||
if (auto res = secp256k1_ec_pubkey_parse(
|
||||
ctx, &c1, recipient.encryptedAmount.data(), ecGamalEncryptedLength);
|
||||
res != 1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -392,25 +409,30 @@ verifyMultiCiphertextEqualityProof(
|
||||
}
|
||||
}
|
||||
|
||||
if (secp256k1_ec_pubkey_parse(
|
||||
if (auto res = secp256k1_ec_pubkey_parse(
|
||||
ctx,
|
||||
&c2_vec[i],
|
||||
recipient.encryptedAmount.data() + ecGamalEncryptedLength,
|
||||
ecGamalEncryptedLength) != 1)
|
||||
ecGamalEncryptedLength);
|
||||
res != 1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
if (secp256k1_ec_pubkey_parse(
|
||||
ctx, &pk_vec[i], recipient.publicKey.data(), ecPubKeyLength) != 1)
|
||||
if (auto res = secp256k1_ec_pubkey_parse(
|
||||
ctx, &pk_vec[i], recipient.publicKey.data(), ecPubKeyLength);
|
||||
res != 1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if (auto res = secp256k1_mpt_verify_equality_shared_r(
|
||||
ctx, proof.data(), nRecipients, &c1, c2_vec.data(), pk_vec.data(), contextHash.data());
|
||||
res != 1)
|
||||
{
|
||||
return tecBAD_PROOF;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
@@ -427,20 +449,30 @@ verifyClawbackEqualityProof(
|
||||
proof.size() != ecEqualityProofLength)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
secp256k1_pubkey c1, c2;
|
||||
if (!makeEcPair(ciphertext, c1, c2))
|
||||
auto const pair = makeEcPair(ciphertext);
|
||||
if (!pair)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
secp256k1_pubkey pubKey;
|
||||
if (secp256k1_ec_pubkey_parse(
|
||||
secp256k1Context(), &pubKey, pubKeySlice.data(), ecPubKeyLength) != 1)
|
||||
if (auto res = secp256k1_ec_pubkey_parse(
|
||||
secp256k1Context(), &pubKey, pubKeySlice.data(), ecPubKeyLength);
|
||||
res != 1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// Note: c2, c1 order - the proof is generated with c2 first (the encrypted
|
||||
// message component) because the equality proof structure expects the
|
||||
// message-containing term before the blinding term.
|
||||
if (secp256k1_equality_plaintext_verify(
|
||||
secp256k1Context(), proof.data(), &pubKey, &c2, &c1, amount, contextHash.data()) != 1)
|
||||
if (auto res = secp256k1_equality_plaintext_verify(
|
||||
secp256k1Context(),
|
||||
proof.data(),
|
||||
&pubKey,
|
||||
&pair->c2,
|
||||
&pair->c1,
|
||||
amount,
|
||||
contextHash.data());
|
||||
res != 1)
|
||||
{
|
||||
return tecBAD_PROOF;
|
||||
}
|
||||
@@ -487,8 +519,8 @@ verifyAmountPcmLinkage(
|
||||
if (proof.length() != ecPedersenProofLength)
|
||||
return tecINTERNAL;
|
||||
|
||||
secp256k1_pubkey c1, c2;
|
||||
if (!makeEcPair(encAmt, c1, c2))
|
||||
auto const pair = makeEcPair(encAmt);
|
||||
if (!pair)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (pubKeySlice.size() != ecPubKeyLength)
|
||||
@@ -498,17 +530,30 @@ verifyAmountPcmLinkage(
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
secp256k1_pubkey pubKey;
|
||||
if (secp256k1_ec_pubkey_parse(
|
||||
secp256k1Context(), &pubKey, pubKeySlice.data(), ecPubKeyLength) != 1)
|
||||
if (auto res = secp256k1_ec_pubkey_parse(
|
||||
secp256k1Context(), &pubKey, pubKeySlice.data(), ecPubKeyLength);
|
||||
res != 1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
secp256k1_pubkey pcm;
|
||||
if (secp256k1_ec_pubkey_parse(
|
||||
secp256k1Context(), &pcm, pcmSlice.data(), ecPedersenCommitmentLength) != 1)
|
||||
if (auto res = secp256k1_ec_pubkey_parse(
|
||||
secp256k1Context(), &pcm, pcmSlice.data(), ecPedersenCommitmentLength);
|
||||
res != 1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
if (secp256k1_elgamal_pedersen_link_verify(
|
||||
secp256k1Context(), proof.data(), &c1, &c2, &pubKey, &pcm, contextHash.data()) != 1)
|
||||
if (auto res = secp256k1_elgamal_pedersen_link_verify(
|
||||
secp256k1Context(),
|
||||
proof.data(),
|
||||
&pair->c1,
|
||||
&pair->c2,
|
||||
&pubKey,
|
||||
&pcm,
|
||||
contextHash.data());
|
||||
res != 1)
|
||||
{
|
||||
return tecBAD_PROOF;
|
||||
}
|
||||
@@ -527,10 +572,8 @@ verifyBalancePcmLinkage(
|
||||
if (proof.length() != ecPedersenProofLength)
|
||||
return tecINTERNAL;
|
||||
|
||||
secp256k1_pubkey c1;
|
||||
secp256k1_pubkey c2;
|
||||
|
||||
if (!makeEcPair(encAmt, c1, c2))
|
||||
auto const pair = makeEcPair(encAmt);
|
||||
if (!pair)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (pubKeySlice.size() != ecPubKeyLength)
|
||||
@@ -540,19 +583,32 @@ verifyBalancePcmLinkage(
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
secp256k1_pubkey pubKey;
|
||||
if (secp256k1_ec_pubkey_parse(
|
||||
secp256k1Context(), &pubKey, pubKeySlice.data(), ecPubKeyLength) != 1)
|
||||
if (auto res = secp256k1_ec_pubkey_parse(
|
||||
secp256k1Context(), &pubKey, pubKeySlice.data(), ecPubKeyLength);
|
||||
res != 1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
secp256k1_pubkey pcm;
|
||||
if (secp256k1_ec_pubkey_parse(
|
||||
secp256k1Context(), &pcm, pcmSlice.data(), ecPedersenCommitmentLength) != 1)
|
||||
if (auto res = secp256k1_ec_pubkey_parse(
|
||||
secp256k1Context(), &pcm, pcmSlice.data(), ecPedersenCommitmentLength);
|
||||
res != 1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// Note: c2, c1 order - the linkage proof expects the message-containing
|
||||
// component (c2 = m*G + r*Pk) before the blinding component (c1 = r*G).
|
||||
if (secp256k1_elgamal_pedersen_link_verify(
|
||||
secp256k1Context(), proof.data(), &pubKey, &c2, &c1, &pcm, contextHash.data()) != 1)
|
||||
if (auto res = secp256k1_elgamal_pedersen_link_verify(
|
||||
secp256k1Context(),
|
||||
proof.data(),
|
||||
&pubKey,
|
||||
&pair->c2,
|
||||
&pair->c1,
|
||||
&pcm,
|
||||
contextHash.data());
|
||||
res != 1)
|
||||
{
|
||||
return tecBAD_PROOF;
|
||||
}
|
||||
@@ -586,12 +642,12 @@ verifyAggregatedBulletproof(
|
||||
if (compressedCommitments[i].size() != ecPedersenCommitmentLength)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (secp256k1_ec_pubkey_parse(
|
||||
ctx,
|
||||
&commitments[i],
|
||||
compressedCommitments[i].data(),
|
||||
ecPedersenCommitmentLength) != 1)
|
||||
if (auto res = secp256k1_ec_pubkey_parse(
|
||||
ctx, &commitments[i], compressedCommitments[i].data(), ecPedersenCommitmentLength);
|
||||
res != 1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Prepare Generator Vectors (G_vec, H_vec)
|
||||
@@ -601,37 +657,42 @@ verifyAggregatedBulletproof(
|
||||
std::vector<secp256k1_pubkey> H_vec(n);
|
||||
|
||||
// Retrieve deterministic generators "G" and "H"
|
||||
if (secp256k1_mpt_get_generator_vector(ctx, G_vec.data(), n, (unsigned char const*)"G", 1) != 1)
|
||||
if (auto res =
|
||||
secp256k1_mpt_get_generator_vector(ctx, G_vec.data(), n, (unsigned char const*)"G", 1);
|
||||
res != 1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
if (secp256k1_mpt_get_generator_vector(ctx, H_vec.data(), n, (unsigned char const*)"H", 1) != 1)
|
||||
if (auto res =
|
||||
secp256k1_mpt_get_generator_vector(ctx, H_vec.data(), n, (unsigned char const*)"H", 1);
|
||||
res != 1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// 4. Prepare Base Generator (pk_base / H)
|
||||
secp256k1_pubkey pk_base;
|
||||
if (secp256k1_mpt_get_h_generator(ctx, &pk_base) != 1)
|
||||
if (auto res = secp256k1_mpt_get_h_generator(ctx, &pk_base); res != 1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// 5. Verify the Proof
|
||||
int const result = secp256k1_bulletproof_verify_agg(
|
||||
ctx,
|
||||
G_vec.data(),
|
||||
H_vec.data(),
|
||||
reinterpret_cast<unsigned char const*>(proof.data()),
|
||||
proof.size(),
|
||||
commitments.data(),
|
||||
m,
|
||||
&pk_base,
|
||||
contextHash.data());
|
||||
|
||||
if (result != 1)
|
||||
if (auto res = secp256k1_bulletproof_verify_agg(
|
||||
ctx,
|
||||
G_vec.data(),
|
||||
H_vec.data(),
|
||||
reinterpret_cast<unsigned char const*>(proof.data()),
|
||||
proof.size(),
|
||||
commitments.data(),
|
||||
m,
|
||||
&pk_base,
|
||||
contextHash.data());
|
||||
res != 1)
|
||||
{
|
||||
return tecBAD_PROOF;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
@@ -646,37 +707,50 @@ computeSendRemainder(Slice const& balanceCommitment, Slice const& amountCommitme
|
||||
auto const ctx = secp256k1Context();
|
||||
|
||||
secp256k1_pubkey pcBalance;
|
||||
if (secp256k1_ec_pubkey_parse(
|
||||
ctx, &pcBalance, balanceCommitment.data(), ecPedersenCommitmentLength) != 1)
|
||||
if (auto res = secp256k1_ec_pubkey_parse(
|
||||
ctx, &pcBalance, balanceCommitment.data(), ecPedersenCommitmentLength);
|
||||
res != 1)
|
||||
{
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
secp256k1_pubkey pcAmount;
|
||||
if (secp256k1_ec_pubkey_parse(
|
||||
ctx, &pcAmount, amountCommitment.data(), ecPedersenCommitmentLength) != 1)
|
||||
if (auto res = secp256k1_ec_pubkey_parse(
|
||||
ctx, &pcAmount, amountCommitment.data(), ecPedersenCommitmentLength);
|
||||
res != 1)
|
||||
{
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
// Negate PC_amount point to get -PC_amount
|
||||
if (!secp256k1_ec_pubkey_negate(ctx, &pcAmount))
|
||||
if (auto res = secp256k1_ec_pubkey_negate(ctx, &pcAmount); res != 1)
|
||||
{
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
// Compute pcRem = pcBalance + (-pcAmount)
|
||||
secp256k1_pubkey const* summands[2] = {&pcBalance, &pcAmount};
|
||||
secp256k1_pubkey pcRem;
|
||||
if (!secp256k1_ec_pubkey_combine(ctx, &pcRem, summands, 2))
|
||||
if (auto res = secp256k1_ec_pubkey_combine(ctx, &pcRem, summands, 2); res != 1)
|
||||
{
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
// Serialize result to compressed format
|
||||
out.alloc(ecPedersenCommitmentLength);
|
||||
size_t outLen = ecPedersenCommitmentLength;
|
||||
if (secp256k1_ec_pubkey_serialize(ctx, out.data(), &outLen, &pcRem, SECP256K1_EC_COMPRESSED) !=
|
||||
1)
|
||||
if (auto res = secp256k1_ec_pubkey_serialize(
|
||||
ctx, out.data(), &outLen, &pcRem, SECP256K1_EC_COMPRESSED);
|
||||
res != 1)
|
||||
{
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
computeConvertBackRemainder(Slice const& commitment, std::uint64_t amount, Buffer& out)
|
||||
computeConvertBackRemainder(Slice const& commitment, uint64_t amount, Buffer& out)
|
||||
{
|
||||
if (commitment.size() != ecPedersenCommitmentLength || amount == 0)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
@@ -685,37 +759,48 @@ computeConvertBackRemainder(Slice const& commitment, std::uint64_t amount, Buffe
|
||||
|
||||
// Parse commitment from compressed format
|
||||
secp256k1_pubkey pcBalance;
|
||||
if (secp256k1_ec_pubkey_parse(ctx, &pcBalance, commitment.data(), ecPedersenCommitmentLength) !=
|
||||
1)
|
||||
if (auto res = secp256k1_ec_pubkey_parse(
|
||||
ctx, &pcBalance, commitment.data(), ecPedersenCommitmentLength);
|
||||
res != 1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// Convert amount to 32-byte big-endian scalar
|
||||
unsigned char mScalar[32] = {0};
|
||||
std::uint64_t amountBigEndian = boost::endian::native_to_big(amount);
|
||||
uint64_t amountBigEndian = boost::endian::native_to_big(amount);
|
||||
std::memcpy(&mScalar[24], &amountBigEndian, sizeof(amountBigEndian));
|
||||
|
||||
// Compute mG = amount * G
|
||||
secp256k1_pubkey mG;
|
||||
if (!secp256k1_ec_pubkey_create(ctx, &mG, mScalar))
|
||||
if (auto res = secp256k1_ec_pubkey_create(ctx, &mG, mScalar); res != 1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// Negate mG to get -mG
|
||||
if (!secp256k1_ec_pubkey_negate(ctx, &mG))
|
||||
if (auto res = secp256k1_ec_pubkey_negate(ctx, &mG); res != 1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// Compute pcRem = pcBalance + (-mG)
|
||||
secp256k1_pubkey const* summands[2] = {&pcBalance, &mG};
|
||||
secp256k1_pubkey pcRem;
|
||||
if (!secp256k1_ec_pubkey_combine(ctx, &pcRem, summands, 2))
|
||||
if (auto res = secp256k1_ec_pubkey_combine(ctx, &pcRem, summands, 2); res != 1)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// Serialize result to compressed format
|
||||
out.alloc(ecPedersenCommitmentLength);
|
||||
size_t outLen = ecPedersenCommitmentLength;
|
||||
if (secp256k1_ec_pubkey_serialize(ctx, out.data(), &outLen, &pcRem, SECP256K1_EC_COMPRESSED) !=
|
||||
1 ||
|
||||
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 tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -117,14 +117,14 @@ ConfidentialMPTClawback::doApply()
|
||||
if (!encZeroForHolder)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
auto const encZeroForIssuer = encryptCanonicalZeroAmount(issuerPubKey, holder, mptIssuanceID);
|
||||
auto encZeroForIssuer = encryptCanonicalZeroAmount(issuerPubKey, holder, mptIssuanceID);
|
||||
if (!encZeroForIssuer)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
// Set holder's confidential balances to encrypted zero
|
||||
(*sleHolderMPToken)[sfConfidentialBalanceInbox] = *encZeroForHolder;
|
||||
(*sleHolderMPToken)[sfConfidentialBalanceSpending] = *encZeroForHolder;
|
||||
(*sleHolderMPToken)[sfIssuerEncryptedBalance] = *encZeroForIssuer;
|
||||
(*sleHolderMPToken)[sfIssuerEncryptedBalance] = std::move(*encZeroForIssuer);
|
||||
incrementConfidentialVersion(*sleHolderMPToken);
|
||||
|
||||
if (sleHolderMPToken->isFieldPresent(sfAuditorEncryptedBalance))
|
||||
@@ -136,13 +136,12 @@ ConfidentialMPTClawback::doApply()
|
||||
|
||||
Slice const auditorPubKey = (*sleIssuance)[sfAuditorElGamalPublicKey];
|
||||
|
||||
auto const encZeroForAuditor =
|
||||
encryptCanonicalZeroAmount(auditorPubKey, holder, mptIssuanceID);
|
||||
auto encZeroForAuditor = encryptCanonicalZeroAmount(auditorPubKey, holder, mptIssuanceID);
|
||||
|
||||
if (!encZeroForAuditor)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
(*sleHolderMPToken)[sfAuditorEncryptedBalance] = *encZeroForAuditor;
|
||||
(*sleHolderMPToken)[sfAuditorEncryptedBalance] = std::move(*encZeroForAuditor);
|
||||
}
|
||||
|
||||
// Decrease Global Confidential Outstanding Amount
|
||||
|
||||
@@ -189,36 +189,30 @@ ConfidentialMPTConvert::doApply()
|
||||
{
|
||||
// Case 1: Add to existing inbox balance (holder will merge later)
|
||||
{
|
||||
Buffer sum(ecGamalEncryptedTotalLength);
|
||||
if (TER const ter =
|
||||
homomorphicAdd(holderEc, (*sleMptoken)[sfConfidentialBalanceInbox], sum);
|
||||
!isTesSuccess(ter))
|
||||
auto sum = homomorphicAdd(holderEc, (*sleMptoken)[sfConfidentialBalanceInbox]);
|
||||
if (!sum)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
(*sleMptoken)[sfConfidentialBalanceInbox] = sum;
|
||||
(*sleMptoken)[sfConfidentialBalanceInbox] = std::move(*sum);
|
||||
}
|
||||
|
||||
// homomorphically add issuer's encrypted balance
|
||||
{
|
||||
Buffer sum(ecGamalEncryptedTotalLength);
|
||||
if (TER const ter =
|
||||
homomorphicAdd(issuerEc, (*sleMptoken)[sfIssuerEncryptedBalance], sum);
|
||||
!isTesSuccess(ter))
|
||||
auto sum = homomorphicAdd(issuerEc, (*sleMptoken)[sfIssuerEncryptedBalance]);
|
||||
if (!sum)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
(*sleMptoken)[sfIssuerEncryptedBalance] = sum;
|
||||
(*sleMptoken)[sfIssuerEncryptedBalance] = std::move(*sum);
|
||||
}
|
||||
|
||||
// homomorphically add auditor's encrypted balance
|
||||
if (auditorEc)
|
||||
{
|
||||
Buffer sum(ecGamalEncryptedTotalLength);
|
||||
if (TER const ter =
|
||||
homomorphicAdd(*auditorEc, (*sleMptoken)[sfAuditorEncryptedBalance], sum);
|
||||
!isTesSuccess(ter))
|
||||
auto sum = homomorphicAdd(*auditorEc, (*sleMptoken)[sfAuditorEncryptedBalance]);
|
||||
if (!sum)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
(*sleMptoken)[sfAuditorEncryptedBalance] = sum;
|
||||
(*sleMptoken)[sfAuditorEncryptedBalance] = std::move(*sum);
|
||||
}
|
||||
}
|
||||
else if (
|
||||
@@ -236,13 +230,13 @@ ConfidentialMPTConvert::doApply()
|
||||
|
||||
// Spending balance starts at zero. Must use canonical zero encryption
|
||||
// (deterministic ciphertext) so the ledger state is reproducible.
|
||||
auto const zeroBalance = encryptCanonicalZeroAmount(
|
||||
auto zeroBalance = encryptCanonicalZeroAmount(
|
||||
(*sleMptoken)[sfHolderElGamalPublicKey], account_, mptIssuanceID);
|
||||
|
||||
if (!zeroBalance)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
(*sleMptoken)[sfConfidentialBalanceSpending] = *zeroBalance;
|
||||
(*sleMptoken)[sfConfidentialBalanceSpending] = std::move(*zeroBalance);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -256,37 +256,32 @@ ConfidentialMPTConvertBack::doApply()
|
||||
|
||||
// homomorphically subtract holder's encrypted balance
|
||||
{
|
||||
Buffer res(ecGamalEncryptedTotalLength);
|
||||
if (TER const ter = homomorphicSubtract(
|
||||
(*sleMptoken)[sfConfidentialBalanceSpending],
|
||||
ctx_.tx[sfHolderEncryptedAmount],
|
||||
res);
|
||||
!isTesSuccess(ter))
|
||||
auto res = homomorphicSubtract(
|
||||
(*sleMptoken)[sfConfidentialBalanceSpending], ctx_.tx[sfHolderEncryptedAmount]);
|
||||
if (!res)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
(*sleMptoken)[sfConfidentialBalanceSpending] = res;
|
||||
(*sleMptoken)[sfConfidentialBalanceSpending] = std::move(*res);
|
||||
}
|
||||
|
||||
// homomorphically subtract issuer's encrypted balance
|
||||
{
|
||||
Buffer res(ecGamalEncryptedTotalLength);
|
||||
if (TER const ter = homomorphicSubtract(
|
||||
(*sleMptoken)[sfIssuerEncryptedBalance], ctx_.tx[sfIssuerEncryptedAmount], res);
|
||||
!isTesSuccess(ter))
|
||||
auto res = homomorphicSubtract(
|
||||
(*sleMptoken)[sfIssuerEncryptedBalance], ctx_.tx[sfIssuerEncryptedAmount]);
|
||||
if (!res)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
(*sleMptoken)[sfIssuerEncryptedBalance] = res;
|
||||
(*sleMptoken)[sfIssuerEncryptedBalance] = std::move(*res);
|
||||
}
|
||||
|
||||
if (auditorEc)
|
||||
{
|
||||
Buffer res(ecGamalEncryptedTotalLength);
|
||||
if (TER const ter = homomorphicSubtract(
|
||||
(*sleMptoken)[sfAuditorEncryptedBalance], ctx_.tx[sfAuditorEncryptedAmount], res);
|
||||
!isTesSuccess(ter))
|
||||
auto res = homomorphicSubtract(
|
||||
(*sleMptoken)[sfAuditorEncryptedBalance], ctx_.tx[sfAuditorEncryptedAmount]);
|
||||
if (!res)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
(*sleMptoken)[sfAuditorEncryptedBalance] = res;
|
||||
(*sleMptoken)[sfAuditorEncryptedBalance] = std::move(*res);
|
||||
}
|
||||
|
||||
incrementConfidentialVersion(*sleMptoken);
|
||||
|
||||
@@ -68,25 +68,22 @@ ConfidentialMPTMergeInbox::doApply()
|
||||
// Merge inbox into spending: spending = spending + inbox
|
||||
// This allows holder to use received funds. Without merging, incoming
|
||||
// transfers sit in inbox and cannot be spent or converted back.
|
||||
Buffer sum(ecGamalEncryptedTotalLength);
|
||||
if (TER const ter = homomorphicAdd(
|
||||
(*sleMptoken)[sfConfidentialBalanceSpending],
|
||||
(*sleMptoken)[sfConfidentialBalanceInbox],
|
||||
sum);
|
||||
!isTesSuccess(ter))
|
||||
auto sum = homomorphicAdd(
|
||||
(*sleMptoken)[sfConfidentialBalanceSpending], (*sleMptoken)[sfConfidentialBalanceInbox]);
|
||||
if (!sum)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
(*sleMptoken)[sfConfidentialBalanceSpending] = sum;
|
||||
(*sleMptoken)[sfConfidentialBalanceSpending] = std::move(*sum);
|
||||
|
||||
// Reset inbox to encrypted zero. Must use canonical zero encryption
|
||||
// (deterministic ciphertext) so the ledger state is reproducible.
|
||||
auto const zeroEncryption = encryptCanonicalZeroAmount(
|
||||
auto zeroEncryption = encryptCanonicalZeroAmount(
|
||||
(*sleMptoken)[sfHolderElGamalPublicKey], account_, mptIssuanceID);
|
||||
|
||||
if (!zeroEncryption)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
(*sleMptoken)[sfConfidentialBalanceInbox] = *zeroEncryption;
|
||||
(*sleMptoken)[sfConfidentialBalanceInbox] = std::move(*zeroEncryption);
|
||||
|
||||
incrementConfidentialVersion(*sleMptoken);
|
||||
|
||||
|
||||
@@ -338,74 +338,63 @@ ConfidentialMPTSend::doApply()
|
||||
// Subtract from sender's spending balance
|
||||
{
|
||||
Slice const curSpending = (*sleSenderMPToken)[sfConfidentialBalanceSpending];
|
||||
Buffer newSpending(ecGamalEncryptedTotalLength);
|
||||
|
||||
if (TER const ter = homomorphicSubtract(curSpending, senderEc, newSpending);
|
||||
!isTesSuccess(ter))
|
||||
auto newSpending = homomorphicSubtract(curSpending, senderEc);
|
||||
if (!newSpending)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
(*sleSenderMPToken)[sfConfidentialBalanceSpending] = newSpending;
|
||||
(*sleSenderMPToken)[sfConfidentialBalanceSpending] = std::move(*newSpending);
|
||||
}
|
||||
|
||||
// Subtract from issuer's balance
|
||||
{
|
||||
Slice const curIssuerEnc = (*sleSenderMPToken)[sfIssuerEncryptedBalance];
|
||||
Buffer newIssuerEnc(ecGamalEncryptedTotalLength);
|
||||
|
||||
if (TER const ter = homomorphicSubtract(curIssuerEnc, issuerEc, newIssuerEnc);
|
||||
!isTesSuccess(ter))
|
||||
auto newIssuerEnc = homomorphicSubtract(curIssuerEnc, issuerEc);
|
||||
if (!newIssuerEnc)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
(*sleSenderMPToken)[sfIssuerEncryptedBalance] = newIssuerEnc;
|
||||
(*sleSenderMPToken)[sfIssuerEncryptedBalance] = std::move(*newIssuerEnc);
|
||||
}
|
||||
|
||||
// Subtract from auditor's balance if present
|
||||
if (auditorEc)
|
||||
{
|
||||
Slice const curAuditorEnc = (*sleSenderMPToken)[sfAuditorEncryptedBalance];
|
||||
Buffer newAuditorEnc(ecGamalEncryptedTotalLength);
|
||||
|
||||
if (TER const ter = homomorphicSubtract(curAuditorEnc, *auditorEc, newAuditorEnc);
|
||||
!isTesSuccess(ter))
|
||||
auto newAuditorEnc = homomorphicSubtract(curAuditorEnc, *auditorEc);
|
||||
if (!newAuditorEnc)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
(*sleSenderMPToken)[sfAuditorEncryptedBalance] = newAuditorEnc;
|
||||
(*sleSenderMPToken)[sfAuditorEncryptedBalance] = std::move(*newAuditorEnc);
|
||||
}
|
||||
|
||||
// Add to destination's inbox balance
|
||||
{
|
||||
Slice const curInbox = (*sleDestinationMPToken)[sfConfidentialBalanceInbox];
|
||||
Buffer newInbox(ecGamalEncryptedTotalLength);
|
||||
|
||||
if (TER const ter = homomorphicAdd(curInbox, destEc, newInbox); !isTesSuccess(ter))
|
||||
auto newInbox = homomorphicAdd(curInbox, destEc);
|
||||
if (!newInbox)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
(*sleDestinationMPToken)[sfConfidentialBalanceInbox] = newInbox;
|
||||
(*sleDestinationMPToken)[sfConfidentialBalanceInbox] = std::move(*newInbox);
|
||||
}
|
||||
|
||||
// Add to issuer's balance
|
||||
{
|
||||
Slice const curIssuerEnc = (*sleDestinationMPToken)[sfIssuerEncryptedBalance];
|
||||
Buffer newIssuerEnc(ecGamalEncryptedTotalLength);
|
||||
|
||||
if (TER const ter = homomorphicAdd(curIssuerEnc, issuerEc, newIssuerEnc);
|
||||
!isTesSuccess(ter))
|
||||
auto newIssuerEnc = homomorphicAdd(curIssuerEnc, issuerEc);
|
||||
if (!newIssuerEnc)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
(*sleDestinationMPToken)[sfIssuerEncryptedBalance] = newIssuerEnc;
|
||||
(*sleDestinationMPToken)[sfIssuerEncryptedBalance] = std::move(*newIssuerEnc);
|
||||
}
|
||||
|
||||
// Add to auditor's balance if present
|
||||
if (auditorEc)
|
||||
{
|
||||
Slice const curAuditorEnc = (*sleDestinationMPToken)[sfAuditorEncryptedBalance];
|
||||
Buffer newAuditorEnc(ecGamalEncryptedTotalLength);
|
||||
|
||||
if (TER const ter = homomorphicAdd(curAuditorEnc, *auditorEc, newAuditorEnc);
|
||||
!isTesSuccess(ter))
|
||||
auto newAuditorEnc = homomorphicAdd(curAuditorEnc, *auditorEc);
|
||||
if (!newAuditorEnc)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
(*sleDestinationMPToken)[sfAuditorEncryptedBalance] = newAuditorEnc;
|
||||
(*sleDestinationMPToken)[sfAuditorEncryptedBalance] = std::move(*newAuditorEnc);
|
||||
}
|
||||
|
||||
// increment sender version only; receiver version is not modified by incoming sends
|
||||
|
||||
@@ -1629,10 +1629,8 @@ MPTTester::decryptAmount(Account const& account, Buffer const& amt) const
|
||||
if (amt.size() != ecGamalEncryptedTotalLength)
|
||||
return std::nullopt;
|
||||
|
||||
secp256k1_pubkey c1;
|
||||
secp256k1_pubkey c2;
|
||||
|
||||
if (!makeEcPair(amt, c1, c2))
|
||||
auto const pair = makeEcPair(amt);
|
||||
if (!pair)
|
||||
return std::nullopt;
|
||||
|
||||
auto const privKey = getPrivKey(account);
|
||||
@@ -1640,7 +1638,8 @@ MPTTester::decryptAmount(Account const& account, Buffer const& amt) const
|
||||
return std::nullopt;
|
||||
|
||||
uint64_t decryptedAmt;
|
||||
if (!secp256k1_elgamal_decrypt(secp256k1Context(), &decryptedAmt, &c1, &c2, privKey->data()))
|
||||
if (!secp256k1_elgamal_decrypt(
|
||||
secp256k1Context(), &decryptedAmt, &pair->c1, &pair->c2, privKey->data()))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user