mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-06 02:07:07 +00:00
Pedersen commitment with ConvertBack and basic test (#6243)
This commit is contained in:
@@ -428,9 +428,9 @@ verifyPedersenLinkage(
|
||||
if (secp256k1_elgamal_pedersen_link_verify(
|
||||
secp256k1Context(),
|
||||
proof.data(),
|
||||
&c1,
|
||||
&c2,
|
||||
&pubKey,
|
||||
&c2,
|
||||
&c1,
|
||||
&pcm,
|
||||
contextHash.data()) != 1)
|
||||
return tecBAD_PROOF;
|
||||
|
||||
@@ -3026,6 +3026,201 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testConvertBackProof(FeatureBitset features)
|
||||
{
|
||||
testcase("Convert back proof");
|
||||
using namespace test::jtx;
|
||||
|
||||
Env env{*this, features};
|
||||
Account const alice("alice");
|
||||
Account const bob("bob");
|
||||
MPTTester mptAlice(env, alice, {.holders = {bob}});
|
||||
|
||||
mptAlice.create(
|
||||
{.ownerCount = 1,
|
||||
.holderCount = 0,
|
||||
.flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanPrivacy});
|
||||
|
||||
mptAlice.authorize({.account = bob});
|
||||
mptAlice.pay(alice, bob, 100);
|
||||
|
||||
mptAlice.generateKeyPair(alice);
|
||||
|
||||
mptAlice.set(
|
||||
{.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
|
||||
|
||||
mptAlice.generateKeyPair(bob);
|
||||
|
||||
mptAlice.convert({
|
||||
.account = bob,
|
||||
.amt = 40,
|
||||
.holderPubKey = mptAlice.getPubKey(bob),
|
||||
});
|
||||
|
||||
mptAlice.mergeInbox({
|
||||
.account = bob,
|
||||
});
|
||||
|
||||
// for ease of understanding, generate all the fields here instead of
|
||||
// autofilling
|
||||
uint64_t const amt = 10;
|
||||
Buffer const blindingFactor = generateBlindingFactor();
|
||||
Buffer const pcBlindingFactor = generateBlindingFactor();
|
||||
uint64_t const spendingBalance = mptAlice.getDecryptedBalance(
|
||||
bob, MPTTester::HOLDER_ENCRYPTED_SPENDING);
|
||||
auto const encryptedSpendingBalance = mptAlice.getEncryptedBalance(
|
||||
bob, MPTTester::HOLDER_ENCRYPTED_SPENDING);
|
||||
|
||||
BEAST_EXPECT(encryptedSpendingBalance);
|
||||
|
||||
Buffer const pedersenCommitment =
|
||||
mptAlice.getPedersenCommitment(spendingBalance, pcBlindingFactor);
|
||||
Buffer const issuerCiphertext =
|
||||
mptAlice.encryptAmount(alice, amt, blindingFactor);
|
||||
Buffer const bobCiphertext =
|
||||
mptAlice.encryptAmount(bob, amt, blindingFactor);
|
||||
auto const version = mptAlice.getMPTokenVersion(bob);
|
||||
|
||||
// generate a proof using a pedersen commitment using the wrong value
|
||||
{
|
||||
uint256 const contextHash = getConvertBackContextHash(
|
||||
bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
|
||||
Buffer const badPedersenCommitment =
|
||||
mptAlice.getPedersenCommitment(1, pcBlindingFactor);
|
||||
Buffer const proof = mptAlice.getConvertBackProof(
|
||||
bob,
|
||||
amt,
|
||||
contextHash,
|
||||
bobCiphertext,
|
||||
issuerCiphertext,
|
||||
{},
|
||||
blindingFactor,
|
||||
{
|
||||
.pedersenCommitment =
|
||||
badPedersenCommitment, // bad pedersen commitment
|
||||
.amt = spendingBalance,
|
||||
.encryptedAmt = *encryptedSpendingBalance,
|
||||
.blindingFactor = pcBlindingFactor,
|
||||
});
|
||||
|
||||
mptAlice.convertBack(
|
||||
{.account = bob,
|
||||
.amt = amt,
|
||||
.proof = proof,
|
||||
.holderEncryptedAmt = bobCiphertext,
|
||||
.issuerEncryptedAmt = issuerCiphertext,
|
||||
.blindingFactor = blindingFactor,
|
||||
.pedersenCommitment = pedersenCommitment,
|
||||
.err = tecBAD_PROOF});
|
||||
}
|
||||
|
||||
// test when the pedersen commitment is wrong while the proof is
|
||||
// right
|
||||
{
|
||||
// generate the context hash again because bob's sequence
|
||||
// incremented from prev txn
|
||||
uint256 const contextHash = getConvertBackContextHash(
|
||||
bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
|
||||
|
||||
Buffer const badPedersenCommitment =
|
||||
mptAlice.getPedersenCommitment(1, pcBlindingFactor);
|
||||
Buffer const proof = mptAlice.getConvertBackProof(
|
||||
bob,
|
||||
amt,
|
||||
contextHash,
|
||||
bobCiphertext,
|
||||
issuerCiphertext,
|
||||
{},
|
||||
blindingFactor,
|
||||
{
|
||||
.pedersenCommitment = pedersenCommitment,
|
||||
.amt = spendingBalance,
|
||||
.encryptedAmt = *encryptedSpendingBalance,
|
||||
.blindingFactor = pcBlindingFactor,
|
||||
});
|
||||
|
||||
mptAlice.convertBack(
|
||||
{.account = bob,
|
||||
.amt = amt,
|
||||
.proof = proof,
|
||||
.holderEncryptedAmt = bobCiphertext,
|
||||
.issuerEncryptedAmt = issuerCiphertext,
|
||||
.blindingFactor = blindingFactor,
|
||||
.pedersenCommitment =
|
||||
badPedersenCommitment, // wrong pc used here
|
||||
.err = tecBAD_PROOF});
|
||||
}
|
||||
|
||||
// the pc blinding factor for generating the pc is different from the
|
||||
// one used to generate pedersen proof
|
||||
{
|
||||
// generate the context hash again because bob's sequence
|
||||
// incremented from prev txn
|
||||
uint256 const contextHash = getConvertBackContextHash(
|
||||
bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
|
||||
|
||||
Buffer const proof = mptAlice.getConvertBackProof(
|
||||
bob,
|
||||
amt,
|
||||
contextHash,
|
||||
bobCiphertext,
|
||||
issuerCiphertext,
|
||||
{},
|
||||
blindingFactor,
|
||||
{
|
||||
.pedersenCommitment = pedersenCommitment,
|
||||
.amt = spendingBalance,
|
||||
.encryptedAmt = *encryptedSpendingBalance,
|
||||
.blindingFactor =
|
||||
generateBlindingFactor(), // bad blinding factor
|
||||
});
|
||||
|
||||
mptAlice.convertBack(
|
||||
{.account = bob,
|
||||
.amt = amt,
|
||||
.proof = proof,
|
||||
.holderEncryptedAmt = bobCiphertext,
|
||||
.issuerEncryptedAmt = issuerCiphertext,
|
||||
.blindingFactor = blindingFactor,
|
||||
.pedersenCommitment = pedersenCommitment,
|
||||
.err = tecBAD_PROOF});
|
||||
}
|
||||
|
||||
// a correct proof
|
||||
{
|
||||
// generate the context hash again because bob's sequence
|
||||
// incremented from prev txn
|
||||
uint256 const contextHash = getConvertBackContextHash(
|
||||
bob, env.seq(bob), mptAlice.issuanceID(), amt, version);
|
||||
|
||||
Buffer const proof = mptAlice.getConvertBackProof(
|
||||
bob,
|
||||
amt,
|
||||
contextHash,
|
||||
bobCiphertext,
|
||||
issuerCiphertext,
|
||||
{},
|
||||
blindingFactor,
|
||||
{
|
||||
.pedersenCommitment = pedersenCommitment,
|
||||
.amt = spendingBalance,
|
||||
.encryptedAmt = *encryptedSpendingBalance,
|
||||
.blindingFactor = pcBlindingFactor,
|
||||
});
|
||||
|
||||
mptAlice.convertBack({
|
||||
.account = bob,
|
||||
.amt = amt,
|
||||
.proof = proof,
|
||||
.holderEncryptedAmt = bobCiphertext,
|
||||
.issuerEncryptedAmt = issuerCiphertext,
|
||||
.blindingFactor = blindingFactor,
|
||||
.pedersenCommitment = pedersenCommitment,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testWithFeats(FeatureBitset features)
|
||||
{
|
||||
@@ -3060,6 +3255,7 @@ class ConfidentialTransfer_test : public beast::unit_test::suite
|
||||
testConvertBackPreflight(features);
|
||||
testConvertBackPreclaim(features);
|
||||
testConvertBackWithAuditor(features);
|
||||
testConvertBackProof(features);
|
||||
|
||||
testMutatePrivacy(features);
|
||||
}
|
||||
|
||||
@@ -140,7 +140,8 @@ MPTTester::MPTTester(MPTInitDef const& arg)
|
||||
{
|
||||
}
|
||||
|
||||
MPTTester::operator MPT() const
|
||||
MPTTester::
|
||||
operator MPT() const
|
||||
{
|
||||
if (!id_)
|
||||
Throw<std::runtime_error>("MPT has not been created");
|
||||
@@ -694,7 +695,8 @@ MPTTester::mpt(std::int64_t amount) const
|
||||
return ripple::test::jtx::MPT(issuer_.name(), *id_)(amount);
|
||||
}
|
||||
|
||||
MPTTester::operator Asset() const
|
||||
MPTTester::
|
||||
operator Asset() const
|
||||
{
|
||||
if (!id_)
|
||||
Throw<std::runtime_error>("MPT has not been created");
|
||||
@@ -736,7 +738,7 @@ MPTTester::getClawbackProof(
|
||||
Account const& holder,
|
||||
std::uint64_t amount,
|
||||
Buffer const& privateKey,
|
||||
uint256 const& ctxHash) const
|
||||
uint256 const& contextHash) const
|
||||
{
|
||||
if (!id_)
|
||||
Throw<std::runtime_error>("MPT has not been created");
|
||||
@@ -794,7 +796,7 @@ MPTTester::getClawbackProof(
|
||||
&c1,
|
||||
amount,
|
||||
privateKey.data(),
|
||||
ctxHash.data()) != 1)
|
||||
contextHash.data()) != 1)
|
||||
{
|
||||
Throw<std::runtime_error>("Proof generation failed");
|
||||
}
|
||||
@@ -803,7 +805,8 @@ MPTTester::getClawbackProof(
|
||||
}
|
||||
|
||||
Buffer
|
||||
MPTTester::getSchnorrProof(Account const& account, uint256 const& ctxHash) const
|
||||
MPTTester::getSchnorrProof(Account const& account, uint256 const& contextHash)
|
||||
const
|
||||
{
|
||||
auto const pubKey = getPubKey(account);
|
||||
auto const privKey = getPrivKey(account);
|
||||
@@ -821,7 +824,7 @@ MPTTester::getSchnorrProof(Account const& account, uint256 const& ctxHash) const
|
||||
proof.data(),
|
||||
&pk,
|
||||
privKey.data(),
|
||||
ctxHash.data()) != 1)
|
||||
contextHash.data()) != 1)
|
||||
{
|
||||
Throw<std::runtime_error>("Schnorr Proof generation failed");
|
||||
}
|
||||
@@ -829,19 +832,53 @@ MPTTester::getSchnorrProof(Account const& account, uint256 const& ctxHash) const
|
||||
return proof;
|
||||
}
|
||||
|
||||
Buffer
|
||||
MPTTester::getPedersenCommitment(
|
||||
std::uint64_t const amount,
|
||||
Buffer const& pedersenBlindingFactor)
|
||||
{
|
||||
// Blinding factor (rho) must be a 32-byte scalar
|
||||
if (pedersenBlindingFactor.size() != ecBlindingFactorLength)
|
||||
Throw<std::runtime_error>("Invalid blinding factor size");
|
||||
|
||||
// current pedersen generation implementation fails if amount is 0
|
||||
if (amount == 0)
|
||||
return Buffer{ecPedersenCommitmentLength};
|
||||
|
||||
secp256k1_pubkey commitment;
|
||||
auto const ctx = secp256k1Context();
|
||||
|
||||
// Compute PC = m*G + rho*H
|
||||
if (secp256k1_mpt_pedersen_commit(
|
||||
ctx, &commitment, amount, pedersenBlindingFactor.data()) != 1)
|
||||
{
|
||||
Throw<std::runtime_error>("Pedersen commitment generation failed");
|
||||
}
|
||||
|
||||
return Buffer{commitment.data, ecPedersenCommitmentLength};
|
||||
}
|
||||
|
||||
Buffer
|
||||
MPTTester::getConvertBackProof(
|
||||
Account const& holder,
|
||||
std::uint64_t amount,
|
||||
uint256 const& ctxHash,
|
||||
std::uint64_t const amount,
|
||||
uint256 const& contextHash,
|
||||
Buffer const& holderCiphertext,
|
||||
Buffer const& issuerCiphertext,
|
||||
std::optional<Buffer> const& auditorCiphertext,
|
||||
Buffer const& blindingFactor) const
|
||||
Buffer const& blindingFactor,
|
||||
PedersenProofParams const& pcParams) const
|
||||
{
|
||||
// todo: incoporate pederson and range proof
|
||||
auto const sleMptoken = env_.le(keylet::mptoken(*id_, holder.id()));
|
||||
if (!sleMptoken ||
|
||||
!sleMptoken->isFieldPresent(sfConfidentialBalanceSpending))
|
||||
return Buffer{};
|
||||
|
||||
return Buffer{};
|
||||
Buffer const pedersenProof = generatePedersenLinkageProof(
|
||||
holder, contextHash, getPubKey(holder), pcParams);
|
||||
|
||||
// todo: incoporate range proof
|
||||
return pedersenProof;
|
||||
}
|
||||
|
||||
std::optional<Buffer>
|
||||
@@ -992,10 +1029,10 @@ 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 ctxHash = getConvertContextHash(
|
||||
auto const contextHash = getConvertContextHash(
|
||||
arg.account->id(), env_.seq(*arg.account), *id_, *arg.amt);
|
||||
|
||||
Buffer proof = getSchnorrProof(*arg.account, ctxHash);
|
||||
Buffer proof = getSchnorrProof(*arg.account, contextHash);
|
||||
jv[sfZKProof.jsonName] = strHex(proof);
|
||||
}
|
||||
|
||||
@@ -1276,10 +1313,10 @@ MPTTester::confidentialClaw(MPTConfidentialClawback const& arg)
|
||||
else
|
||||
{
|
||||
std::uint32_t const seq = env_.seq(account);
|
||||
uint256 const ctxHash = getClawbackContextHash(
|
||||
uint256 const contextHash = getClawbackContextHash(
|
||||
account.id(), seq, *id_, *arg.amt, arg.holder->id());
|
||||
Buffer proof = getClawbackProof(
|
||||
*arg.holder, *arg.amt, getPrivKey(account), ctxHash);
|
||||
*arg.holder, *arg.amt, getPrivKey(account), contextHash);
|
||||
|
||||
jv[sfZKProof] = strHex(proof);
|
||||
}
|
||||
@@ -1538,24 +1575,54 @@ MPTTester::convertBack(MPTConvertBack const& arg)
|
||||
|
||||
jv[sfBlindingFactor] = strHex(blindingFactor);
|
||||
|
||||
uint64_t prevSpendingBalance =
|
||||
getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING);
|
||||
|
||||
Buffer pedersenCommitment;
|
||||
Buffer pcBlindingFactor = generateBlindingFactor();
|
||||
if (arg.pedersenCommitment)
|
||||
pedersenCommitment = *arg.pedersenCommitment;
|
||||
else
|
||||
pedersenCommitment =
|
||||
getPedersenCommitment(prevSpendingBalance, pcBlindingFactor);
|
||||
|
||||
jv[sfPedersenCommitment] = strHex(pedersenCommitment);
|
||||
|
||||
if (arg.proof)
|
||||
jv[sfZKProof.jsonName] = *arg.proof;
|
||||
jv[sfZKProof.jsonName] = strHex(*arg.proof);
|
||||
else
|
||||
{
|
||||
auto const version = getMPTokenVersion(*arg.account);
|
||||
|
||||
// if the caller generated ciphertexts themselves, they should also
|
||||
// generate the proof themselves from the blinding factor
|
||||
uint256 const ctxHash = getConvertBackContextHash(
|
||||
uint256 const contextHash = getConvertBackContextHash(
|
||||
arg.account->id(), env_.seq(*arg.account), *id_, *arg.amt, version);
|
||||
Buffer proof = getConvertBackProof(
|
||||
*arg.account,
|
||||
*arg.amt,
|
||||
ctxHash,
|
||||
holderCiphertext,
|
||||
issuerCiphertext,
|
||||
auditorCiphertext,
|
||||
blindingFactor);
|
||||
auto const prevEncryptedSpendingBalance =
|
||||
getEncryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING);
|
||||
|
||||
Buffer proof;
|
||||
// generate a dummy proof if no encrypted amount field, so that other
|
||||
// preflight/preclaim are checked
|
||||
if (!prevEncryptedSpendingBalance)
|
||||
proof = Buffer();
|
||||
else
|
||||
{
|
||||
proof = getConvertBackProof(
|
||||
*arg.account,
|
||||
*arg.amt,
|
||||
contextHash,
|
||||
holderCiphertext,
|
||||
issuerCiphertext,
|
||||
auditorCiphertext,
|
||||
blindingFactor,
|
||||
{
|
||||
.pedersenCommitment = pedersenCommitment,
|
||||
.amt = prevSpendingBalance,
|
||||
.encryptedAmt = *prevEncryptedSpendingBalance,
|
||||
.blindingFactor = pcBlindingFactor,
|
||||
});
|
||||
}
|
||||
jv[sfZKProof] = strHex(proof);
|
||||
}
|
||||
|
||||
@@ -1564,8 +1631,6 @@ MPTTester::convertBack(MPTConvertBack const& arg)
|
||||
|
||||
uint64_t prevInboxBalance =
|
||||
getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_INBOX);
|
||||
uint64_t prevSpendingBalance =
|
||||
getDecryptedBalance(*arg.account, HOLDER_ENCRYPTED_SPENDING);
|
||||
uint64_t prevIssuerBalance =
|
||||
getDecryptedBalance(*arg.account, ISSUER_ENCRYPTED_BALANCE);
|
||||
[[maybe_unused]] uint64_t prevAuditorBalance =
|
||||
@@ -1620,6 +1685,57 @@ MPTTester::convertBack(MPTConvertBack const& arg)
|
||||
}
|
||||
}
|
||||
|
||||
Buffer
|
||||
MPTTester::generatePedersenLinkageProof(
|
||||
Account const& account,
|
||||
uint256 const& contextHash,
|
||||
Buffer const& pubKey,
|
||||
PedersenProofParams const& params) const
|
||||
{
|
||||
if (params.blindingFactor.size() != ecBlindingFactorLength ||
|
||||
params.pedersenCommitment.size() != ecPedersenCommitmentLength ||
|
||||
pubKey.size() != ecPubKeyLength ||
|
||||
params.encryptedAmt.size() != ecGamalEncryptedTotalLength)
|
||||
return Buffer(ecPedersenProofLength);
|
||||
|
||||
secp256k1_pubkey c1, c2;
|
||||
auto const ctx = secp256k1Context();
|
||||
if (!secp256k1_ec_pubkey_parse(
|
||||
ctx, &c1, params.encryptedAmt.data(), ecGamalEncryptedLength) ||
|
||||
!secp256k1_ec_pubkey_parse(
|
||||
ctx,
|
||||
&c2,
|
||||
params.encryptedAmt.data() + ecGamalEncryptedLength,
|
||||
ecGamalEncryptedLength))
|
||||
{
|
||||
return Buffer();
|
||||
}
|
||||
|
||||
secp256k1_pubkey pk;
|
||||
std::memcpy(pk.data, pubKey.data(), ecPubKeyLength);
|
||||
|
||||
secp256k1_pubkey pcm;
|
||||
std::memcpy(
|
||||
pcm.data, params.pedersenCommitment.data(), ecPedersenCommitmentLength);
|
||||
|
||||
Buffer proof(ecPedersenProofLength);
|
||||
|
||||
if (secp256k1_elgamal_pedersen_link_prove(
|
||||
ctx,
|
||||
proof.data(),
|
||||
&pk,
|
||||
&c2,
|
||||
&c1,
|
||||
&pcm,
|
||||
params.amt,
|
||||
getPrivKey(account).data(),
|
||||
params.blindingFactor.data(),
|
||||
contextHash.data()) != 1)
|
||||
Throw<std::runtime_error>("Pedersen proof generation failed");
|
||||
|
||||
return proof;
|
||||
}
|
||||
|
||||
} // namespace jtx
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
|
||||
@@ -187,7 +187,6 @@ struct MPTConvert
|
||||
std::optional<Buffer> issuerEncryptedAmt = std::nullopt;
|
||||
std::optional<Buffer> auditorEncryptedAmt = std::nullopt;
|
||||
|
||||
// not an txn param, only used for autofilling
|
||||
std::optional<Buffer> blindingFactor = std::nullopt;
|
||||
std::optional<std::uint32_t> ownerCount = std::nullopt;
|
||||
std::optional<std::uint32_t> holderCount = std::nullopt;
|
||||
@@ -231,12 +230,12 @@ struct MPTConvertBack
|
||||
std::optional<Account> account = std::nullopt;
|
||||
std::optional<MPTID> id = std::nullopt;
|
||||
std::optional<std::uint64_t> amt = std::nullopt;
|
||||
std::optional<std::string> proof = std::nullopt;
|
||||
std::optional<Buffer> proof = std::nullopt;
|
||||
std::optional<Buffer> holderEncryptedAmt = std::nullopt;
|
||||
std::optional<Buffer> issuerEncryptedAmt = std::nullopt;
|
||||
std::optional<Buffer> auditorEncryptedAmt = std::nullopt;
|
||||
// not an txn param, only used for autofilling
|
||||
std::optional<Buffer> blindingFactor = std::nullopt;
|
||||
std::optional<Buffer> pedersenCommitment = std::nullopt;
|
||||
std::optional<std::uint32_t> ownerCount = std::nullopt;
|
||||
std::optional<std::uint32_t> holderCount = std::nullopt;
|
||||
std::optional<std::uint32_t> flags = std::nullopt;
|
||||
@@ -256,6 +255,18 @@ struct MPTConfidentialClawback
|
||||
std::optional<TER> err = std::nullopt;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Stores the parameterss that are exclusively used to generate a
|
||||
* pedersen linkage proof
|
||||
*/
|
||||
struct PedersenProofParams
|
||||
{
|
||||
Buffer const pedersenCommitment;
|
||||
uint64_t const amt; // either spending balance or value to be transferred
|
||||
Buffer const encryptedAmt;
|
||||
Buffer const blindingFactor;
|
||||
};
|
||||
|
||||
class MPTTester
|
||||
{
|
||||
Env& env_;
|
||||
@@ -454,21 +465,34 @@ public:
|
||||
uint256 const& txHash) const;
|
||||
|
||||
Buffer
|
||||
getSchnorrProof(Account const& account, uint256 const& ctxHash) const;
|
||||
getSchnorrProof(Account const& account, uint256 const& contextHash) const;
|
||||
|
||||
Buffer
|
||||
getConvertBackProof(
|
||||
Account const& holder,
|
||||
std::uint64_t amount,
|
||||
uint256 const& ctxHash,
|
||||
std::uint64_t const amount,
|
||||
uint256 const& contextHash,
|
||||
Buffer const& holderCiphertext,
|
||||
Buffer const& issuerCiphertext,
|
||||
std::optional<Buffer> const& auditorCiphertext,
|
||||
Buffer const& blindingFactor) const;
|
||||
Buffer const& blindingFactor,
|
||||
PedersenProofParams const& pcParams) const;
|
||||
|
||||
std::uint32_t
|
||||
getMPTokenVersion(Account const account) const;
|
||||
|
||||
Buffer
|
||||
generatePedersenLinkageProof(
|
||||
Account const& account,
|
||||
uint256 const& contextHash,
|
||||
Buffer const& pubKey,
|
||||
PedersenProofParams const& params) const;
|
||||
|
||||
Buffer
|
||||
getPedersenCommitment(
|
||||
std::uint64_t const amount,
|
||||
Buffer const& pedersenBlindingFactor);
|
||||
|
||||
private:
|
||||
using SLEP = SLE::const_pointer;
|
||||
bool
|
||||
|
||||
@@ -28,6 +28,9 @@ ConfidentialConvertBack::preflight(PreflightContext const& ctx)
|
||||
if (ctx.tx[sfBlindingFactor].size() != ecBlindingFactorLength)
|
||||
return temMALFORMED;
|
||||
|
||||
if (ctx.tx[sfPedersenCommitment].size() != ecPedersenCommitmentLength)
|
||||
return temMALFORMED;
|
||||
|
||||
// check encrypted amount format after the above basic checks
|
||||
// this check is more expensive so put it at the end
|
||||
if (auto const res = checkEncryptedAmountFormat(ctx.tx); !isTesSuccess(res))
|
||||
@@ -45,19 +48,18 @@ verifyProofs(
|
||||
if (!mptoken->isFieldPresent(sfHolderElGamalPublicKey))
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
// auto const mptIssuanceID = tx[sfMPTokenIssuanceID];
|
||||
// auto const account = tx[sfAccount];
|
||||
auto const mptIssuanceID = tx[sfMPTokenIssuanceID];
|
||||
auto const account = tx[sfAccount];
|
||||
auto const amount = tx[sfMPTAmount];
|
||||
auto const blindingFactor = tx[sfBlindingFactor];
|
||||
auto const holderPubKey = (*mptoken)[sfHolderElGamalPublicKey];
|
||||
|
||||
// todo: commented out for now, will use for range proof
|
||||
// auto const contextHash = getConvertBackContextHash(
|
||||
// account,
|
||||
// tx[sfSequence],
|
||||
// mptIssuanceID,
|
||||
// amount,
|
||||
// (*mptoken)[~sfConfidentialBalanceVersion].value_or(0));
|
||||
auto const contextHash = getConvertBackContextHash(
|
||||
account,
|
||||
tx[sfSequence],
|
||||
mptIssuanceID,
|
||||
amount,
|
||||
(*mptoken)[~sfConfidentialBalanceVersion].value_or(0));
|
||||
|
||||
// Prepare Auditor Info
|
||||
std::optional<EncryptedAmountInfo> auditor;
|
||||
@@ -82,6 +84,28 @@ verifyProofs(
|
||||
return ter;
|
||||
}
|
||||
|
||||
// Use a pointer to parse each proof component
|
||||
Buffer zkps = Buffer(tx[sfZKProof].data(), tx[sfZKProof].size());
|
||||
std::uint8_t* ptr = zkps.data();
|
||||
|
||||
// verify el gamal pedersen linkage
|
||||
{
|
||||
Buffer const pedersen{ptr, ecPedersenProofLength};
|
||||
if (auto const ter = verifyPedersenLinkage(
|
||||
pedersen,
|
||||
(*mptoken)[sfConfidentialBalanceSpending],
|
||||
holderPubKey,
|
||||
tx[sfPedersenCommitment],
|
||||
contextHash);
|
||||
!isTesSuccess(ter))
|
||||
{
|
||||
return ter;
|
||||
}
|
||||
|
||||
// increment pointer
|
||||
ptr += ecPedersenProofLength;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user