From 462c8736390917947feb099dc691889b1822508f Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Tue, 18 Oct 2022 15:04:11 -0400 Subject: [PATCH 1/4] blindpsbt: Expose CreateBlind{Asset,Value}Proof Make these two functions available to external callers. CreateBlindValueProof is a wrapper around the static function to avoid requiring callers to parse things into secp256k1 objects. --- src/blindpsbt.cpp | 15 ++++++++++++++- src/blindpsbt.h | 2 ++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/blindpsbt.cpp b/src/blindpsbt.cpp index 6910d5ae85..6f6fb59c27 100644 --- a/src/blindpsbt.cpp +++ b/src/blindpsbt.cpp @@ -136,8 +136,21 @@ static bool CreateBlindValueProof(std::vector& rangeproof, const return res == 1; } +bool CreateBlindValueProof(std::vector& rangeproof, const uint256& value_blinder, const CAmount amount, const CConfidentialValue& conf_value, const CConfidentialAsset& conf_asset) +{ + secp256k1_pedersen_commitment value_commit; + int ret = secp256k1_pedersen_commitment_parse(secp256k1_blind_context, &value_commit, conf_value.vchCommitment.data()); + assert(ret == 1); + + secp256k1_generator asset_gen; + ret = secp256k1_generator_parse(secp256k1_blind_context, &asset_gen, conf_asset.vchCommitment.data()); + assert(ret == 1); + + return CreateBlindValueProof(rangeproof, value_blinder, amount, value_commit, asset_gen); +} + // Create an explicit value rangeproof which proves that the commitment commits to an explicit value -static bool CreateBlindAssetProof(std::vector& assetproof, const CAsset& asset, const CConfidentialAsset& asset_commit, const uint256& asset_blinder) +bool CreateBlindAssetProof(std::vector& assetproof, const CAsset& asset, const CConfidentialAsset& asset_commit, const uint256& asset_blinder) { const unsigned char zero32[32] = {0}; secp256k1_surjectionproof proof; diff --git a/src/blindpsbt.h b/src/blindpsbt.h index 49c753db78..e396f18bf1 100644 --- a/src/blindpsbt.h +++ b/src/blindpsbt.h @@ -50,6 +50,8 @@ void CreateValueCommitment(CConfidentialValue& conf_value, secp256k1_pedersen_co BlindingStatus BlindPSBT(PartiallySignedTransaction& psbt, std::map> our_input_data, std::map> our_issuances_to_blind); +bool CreateBlindValueProof(std::vector& rangeproof, const uint256& value_blinder, const CAmount amount, const CConfidentialValue& conf_value, const CConfidentialAsset& conf_asset); +bool CreateBlindAssetProof(std::vector& assetproof, const CAsset& asset, const CConfidentialAsset& asset_commit, const uint256& asset_blinder); bool VerifyBlindValueProof(CAmount value, const CConfidentialValue& conf_value, const std::vector& proof, const CConfidentialAsset& conf_asset); bool VerifyBlindAssetProof(const uint256& asset, const std::vector& proof, const CConfidentialAsset& conf_asset); BlindProofResult VerifyBlindProofs(const PSBTOutput& o); From a584133bd66f612d586440c05646d4e5afb9e2a4 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Tue, 18 Oct 2022 15:08:31 -0400 Subject: [PATCH 2/4] wallet: Add include_explicit to FillPSBT --- src/wallet/wallet.cpp | 18 +++++++++++++++--- src/wallet/wallet.h | 5 +++-- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 87afe5a131..1751f56f05 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -5,6 +5,7 @@ #include +#include #include #include #include @@ -1817,7 +1818,7 @@ bool CWallet::SignTransaction(CMutableTransaction& tx, const std::mapwitness.vtxoutwit.size() && !wtx.tx->witness.vtxoutwit[*input.prev_out].vchRangeproof.empty()) { input.m_utxo_rangeproof = wtx.tx->witness.vtxoutwit[*input.prev_out].vchRangeproof; } + const CTxOut& utxo = wtx.tx->vout[*input.prev_out]; + if (include_explicit && utxo.nAsset.IsCommitment()) { + const CAsset asset = wtx.GetOutputAsset(*input.prev_out); + input.m_explicit_asset = asset.id; + CreateBlindAssetProof(input.m_asset_proof, asset, utxo.nAsset, wtx.GetOutputAssetBlindingFactor(*input.prev_out)); + + if (utxo.nValue.IsCommitment()) { + input.m_explicit_value = wtx.GetOutputValueOut(*input.prev_out); + CreateBlindValueProof(input.m_value_proof, wtx.GetOutputAmountBlindingFactor(*input.prev_out), *input.m_explicit_value, utxo.nValue, utxo.nAsset); + } + } } } } @@ -2109,11 +2121,11 @@ TransactionError CWallet::SignPSBT(PartiallySignedTransaction& psbtx, bool& comp } // This function remains for backwards compatibility. It will not succeed in Elements unless everything involved is non-blinded. -TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& complete, int sighash_type, bool sign, bool bip32derivs, bool imbalance_ok, size_t* n_signed) const +TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& complete, int sighash_type, bool sign, bool bip32derivs, bool imbalance_ok, size_t* n_signed, bool include_explicit) const { complete = false; TransactionError te; - te = FillPSBTData(psbtx, bip32derivs); + te = FillPSBTData(psbtx, bip32derivs, include_explicit); if (te != TransactionError::OK) { return te; } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index aed80ea542..4cc863692e 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -608,10 +608,11 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati bool sign = true, bool bip32derivs = true, bool imbalance_ok = false, - size_t* n_signed = nullptr) const; + size_t* n_signed = nullptr, + bool include_explicit = false) const; // ELEMENTS - TransactionError FillPSBTData(PartiallySignedTransaction& psbtx, bool bip32derivs = false) const; + TransactionError FillPSBTData(PartiallySignedTransaction& psbtx, bool bip32derivs = false, bool include_explicit = false) const; TransactionError SignPSBT(PartiallySignedTransaction& psbtx, bool& complete, int sighash_type = 1, bool sign = true, bool imbalance_ok = false, bool bip32derivs = false, size_t* n_signed = nullptr) const; BlindingStatus WalletBlindPSBT(PartiallySignedTransaction& psbtx) const; // end ELEMENTS From 9dbf0b6f55a504fc7cdb7bfaed52ea15f2e5f7c0 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Tue, 18 Oct 2022 15:08:42 -0400 Subject: [PATCH 3/4] wallet, rpc: Add include_explicit to walletcreatefundedpsbt --- src/wallet/rpcwallet.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index f56e9025a3..1036923dbe 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3337,6 +3337,7 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out, {"replaceable", UniValueType(UniValue::VBOOL)}, {"conf_target", UniValueType(UniValue::VNUM)}, {"estimate_mode", UniValueType(UniValue::VSTR)}, + {"include_explicit", UniValueType(UniValue::VBOOL)}, }, true, true); @@ -4909,6 +4910,7 @@ static RPCHelpMan walletcreatefundedpsbt() {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"}, {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n" " \"" + FeeModes("\"\n\"") + "\""}, + {"include_explicit", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include explicit values and assets and their proofs for blinded inputs"}, }, "options"}, {"bip32derivs", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include BIP 32 derivation paths for public keys if we know them"}, @@ -5089,10 +5091,13 @@ static RPCHelpMan walletcreatefundedpsbt() throw JSONRPCError(RPC_INVALID_PARAMETER, "Missing output for reissuance tokens"); } + // Determine whether to include explicit values + bool include_explicit = request.params[3].exists("include_explicit") && request.params[3]["include_explicit"].get_bool(); + // Fill transaction with out data but don't sign bool bip32derivs = request.params[4].isNull() ? true : request.params[4].get_bool(); bool complete = true; - const TransactionError err{wallet.FillPSBT(psbtx, complete, 1, false, bip32derivs, true)}; + const TransactionError err{wallet.FillPSBT(psbtx, complete, 1, false, bip32derivs, true, nullptr, include_explicit)}; if (err != TransactionError::OK) { throw JSONRPCTransactionError(err); } From 42cbdc81a6c36db0cabb2796e1c1fc955f1bf9ad Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Tue, 18 Oct 2022 15:42:51 -0400 Subject: [PATCH 4/4] test: Test for explicit values and assets and their proofs --- test/functional/rpc_psbt.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py index 8d36b135cb..ded98e4e3b 100755 --- a/test/functional/rpc_psbt.py +++ b/test/functional/rpc_psbt.py @@ -679,6 +679,14 @@ def run_ca_tests(self): self.nodes[0].generate(1) self.sync_all() + # Check include_explicit option + psbt = self.nodes[2].walletcreatefundedpsbt([{"txid": txid_conf_2, "vout": 1}], [{self.get_address(True, 0): 24.998, "blinder_index": 0}, {"fee": 0.001}], 0, {"include_explicit": True})["psbt"] + decoded = self.nodes[1].decodepsbt(psbt) + assert "explicit_value" in decoded["inputs"][0] + assert "value_proof" in decoded["inputs"][0] + assert "explicit_asset" in decoded["inputs"][0] + assert "asset_proof" in decoded["inputs"][0] + # Try to send conf->conf conf_addr_4 = self.get_address(True, 0) psbt = self.nodes[2].createpsbt([{"txid": txid_conf_2, "vout": 1}], [{conf_addr_4: 24.998, "blinder_index": 0}, {"fee": 0.001}])