From 172a959c7afba127dd6a5f028bd2240819583f1f Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 1 Sep 2022 13:17:48 -0400 Subject: [PATCH 1/8] doc: Specify input explicit values and assets and their proofs --- doc/pset.mediawiki | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/doc/pset.mediawiki b/doc/pset.mediawiki index da769b7169..90c8ff73fd 100644 --- a/doc/pset.mediawiki +++ b/doc/pset.mediawiki @@ -255,6 +255,46 @@ The currently defined elements per-input proprietary types are as follows: | | 0 | 2 +|- +| Explicit Value +| PSBT_ELEMENTS_IN_EXPLICIT_VALUE = 0x11 +| None +| No key data +| <64-bit little endian int value> +| The explicit value for the input being spent. If provided, PSBT_ELEMENTS_IN_VALUE_PROOF must be provided too. Must not be provided if the input's value in the UTXO is already explicit. +| +| 0 +| 2 +|- +| Explicit Value Proof +| PSBT_ELEMENTS_IN_VALUE_PROOF = 0x12 +| None +| No key data +| +| An explicit value rangeproof that proves that the value commitment in this input's UTXO matches the explicit value in PSBT_ELEMENTS_IN_EXPLICIT_VALUE. If provided, PSBT_ELEMENTS_IN_EXPLICIT_VALUE must be provided too. +| +| 0 +| 2 +|- +| Explicit Asset +| PSBT_ELEMENTS_IN_EXPLICIT_ASSET = 0x13 +| None +| No key data +| <32 byte asset tag> +| The explicit asset for the input being spent. If provided, PSBT_ELEMENTS_IN_ASSET_PROOF must be provided too. Must not be provided if the input's asset in the UTXO is already explicit. +| +| 0 +| 2 +|- +| Explicit Asset Proof +| PSBT_ELEMENTS_IN_ASSET_PROOF = 0x14 +| None +| No key data +| +| An asset surjection proof with this input's asset as the only asset in the input set in order to prove that the asset commitment in the UTXO matches the explicit asset in PSBT_ELEMENTS_IN_EXPLICIT_ASSET. If provided, PSBT_ELEMENTS_IN_EXPLICIT_ASSET must be provided too. +| +| 0 +| 2 |} The currently defined elements per-output proprietary types are as follows: From 59658ece6d41cb49e6cc77e3b065b764e3a89c41 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 1 Sep 2022 13:18:08 -0400 Subject: [PATCH 2/8] pset: Implement de/ser of input explicit value, assets, and proofs --- src/psbt.h | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/src/psbt.h b/src/psbt.h index 0bd2b3bf73..145410f3b0 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -73,6 +73,10 @@ static constexpr uint8_t PSBT_ELEMENTS_IN_ISSUANCE_ASSET_ENTROPY = 0x0d; static constexpr uint8_t PSBT_ELEMENTS_IN_UTXO_RANGEPROOF = 0x0e; static constexpr uint8_t PSBT_ELEMENTS_IN_ISSUANCE_BLIND_VALUE_PROOF = 0x0f; static constexpr uint8_t PSBT_ELEMENTS_IN_ISSUANCE_BLIND_INFLATION_KEYS_PROOF = 0x10; +static constexpr uint8_t PSBT_ELEMENTS_IN_EXPLICIT_VALUE = 0x11; +static constexpr uint8_t PSBT_ELEMENTS_IN_VALUE_PROOF = 0x12; +static constexpr uint8_t PSBT_ELEMENTS_IN_EXPLICIT_ASSET = 0x13; +static constexpr uint8_t PSBT_ELEMENTS_IN_ASSET_PROOF = 0x14; // Output types static constexpr uint8_t PSBT_OUT_REDEEMSCRIPT = 0x00; @@ -259,6 +263,10 @@ struct PSBTInput // Auxiliary elements stuff std::vector m_utxo_rangeproof; + std::optional m_explicit_value; + std::vector m_value_proof; + uint256 m_explicit_asset; + std::vector m_asset_proof; bool IsNull() const; void FillSignatureData(SignatureData& sigdata) const; @@ -473,6 +481,26 @@ struct PSBTInput SerializeToVector(s, CompactSizeWriter(PSBT_OUT_PROPRIETARY), PSBT_ELEMENTS_ID, CompactSizeWriter(PSBT_ELEMENTS_IN_ISSUANCE_BLIND_INFLATION_KEYS_PROOF)); s << m_blind_issuance_inflation_keys_proof; } + + // Explicit value and its proof + if (m_explicit_value.has_value()) { + SerializeToVector(s, CompactSizeWriter(PSBT_IN_PROPRIETARY), PSBT_ELEMENTS_ID, CompactSizeWriter(PSBT_ELEMENTS_IN_EXPLICIT_VALUE)); + SerializeToVector(s, m_explicit_value.value()); + } + if (!m_value_proof.empty()) { + SerializeToVector(s, CompactSizeWriter(PSBT_IN_PROPRIETARY), PSBT_ELEMENTS_ID, CompactSizeWriter(PSBT_ELEMENTS_IN_VALUE_PROOF)); + s << m_value_proof; + } + + // Explicit asset and its proof + if (!m_explicit_asset.IsNull()) { + SerializeToVector(s, CompactSizeWriter(PSBT_IN_PROPRIETARY), PSBT_ELEMENTS_ID, CompactSizeWriter(PSBT_ELEMENTS_IN_EXPLICIT_ASSET)); + SerializeToVector(s, m_explicit_asset); + } + if (!m_asset_proof.empty()) { + SerializeToVector(s, CompactSizeWriter(PSBT_IN_PROPRIETARY), PSBT_ELEMENTS_ID, CompactSizeWriter(PSBT_ELEMENTS_IN_ASSET_PROOF)); + s << m_asset_proof; + } } // Write proprietary things @@ -886,6 +914,48 @@ struct PSBTInput s >> m_blind_issuance_inflation_keys_proof; break; } + case PSBT_ELEMENTS_IN_EXPLICIT_VALUE: + { + if (!key_lookup.emplace(key).second) { + throw std::ios_base::failure("Duplicate Key, explicit value is already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Input explicit value is more than one byte type"); + } + CAmount v; + UnserializeFromVector(s, v); + m_explicit_value = v; + break; + } + case PSBT_ELEMENTS_IN_VALUE_PROOF: + { + if (!key_lookup.emplace(key).second) { + throw std::ios_base::failure("Duplicate Key, explicit value proof is already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Input explicit value proof is more than one byte type"); + } + s >> m_value_proof; + break; + } + case PSBT_ELEMENTS_IN_EXPLICIT_ASSET: + { + if (!key_lookup.emplace(key).second) { + throw std::ios_base::failure("Duplicate Key, explicit asset is already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Input explicit asset is more than one byte type"); + } + UnserializeFromVector(s, m_explicit_asset); + break; + } + case PSBT_ELEMENTS_IN_ASSET_PROOF: + { + if (!key_lookup.emplace(key).second) { + throw std::ios_base::failure("Duplicate Key, explicit asset proof is already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Input explicit asset proof is more than one byte type"); + } + s >> m_value_proof; + break; + } default: { known = false; @@ -936,6 +1006,12 @@ struct PSBTInput if (!m_issuance_inflation_keys_commitment.IsNull() && m_issuance_inflation_keys_rangeproof.empty()) { throw std::ios_base::failure("Issuance inflation keys commitment provided without inflation keys rangeproof"); } + if ((m_explicit_value.has_value() || !m_value_proof.empty()) && (!m_explicit_value.has_value() || m_value_proof.empty())) { + throw std::ios_base::failure("Input explicit value and value proof must be provided together"); + } + if ((!m_explicit_asset.IsNull() || !m_asset_proof.empty()) && (!m_explicit_asset.IsNull() || m_asset_proof.empty())) { + throw std::ios_base::failure("Input explicit asset and asset proof must be provided together"); + } } } From be602495f95cf7675aa1228195ed187d00f26422 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 1 Sep 2022 13:48:47 -0400 Subject: [PATCH 3/8] pset: Implement VerifyBlindProofs for PSBTInput --- src/blindpsbt.cpp | 29 +++++++++++++++++++++++++++++ src/blindpsbt.h | 2 ++ 2 files changed, 31 insertions(+) diff --git a/src/blindpsbt.cpp b/src/blindpsbt.cpp index c2b927e265..8b964a9f17 100644 --- a/src/blindpsbt.cpp +++ b/src/blindpsbt.cpp @@ -220,6 +220,35 @@ BlindProofResult VerifyBlindProofs(const PSBTOutput& o) { return BlindProofResult::OK; } +BlindProofResult VerifyBlindProofs(const PSBTInput& i) { + CTxOut utxo; + if (!i.GetUTXO(utxo)) { + return BlindProofResult::OK; + } + + if (i.m_explicit_value != std::nullopt) { + if (i.m_value_proof.empty()) { + return BlindProofResult::MISSING_VALUE_PROOF; + } else if (!utxo.nValue.IsCommitment()) { + return BlindProofResult::NOT_FULLY_BLINDED; + } else if (!VerifyBlindValueProof(*i.m_explicit_value, utxo.nValue, i.m_value_proof, utxo.nAsset)) { + return BlindProofResult::INVALID_VALUE_PROOF; + } + } + + if (!i.m_explicit_asset.IsNull()) { + if (i.m_asset_proof.empty()) { + return BlindProofResult::MISSING_ASSET_PROOF; + } else if (!utxo.nAsset.IsCommitment()) { + return BlindProofResult::NOT_FULLY_BLINDED; + } else if (!VerifyBlindAssetProof(i.m_explicit_asset, i.m_asset_proof, utxo.nAsset)) { + return BlindProofResult::INVALID_ASSET_PROOF; + } + } + + return BlindProofResult::OK; +} + void CreateAssetCommitment(CConfidentialAsset& conf_asset, secp256k1_generator& asset_gen, const CAsset& asset, const uint256& asset_blinder) { conf_asset.vchCommitment.resize(CConfidentialAsset::nCommittedSize); diff --git a/src/blindpsbt.h b/src/blindpsbt.h index 17fda2b7d9..49c753db78 100644 --- a/src/blindpsbt.h +++ b/src/blindpsbt.h @@ -17,6 +17,7 @@ struct PartiallySignedTransaction; struct PSBTOutput; +struct PSBTInput; enum class BlindingStatus { @@ -52,5 +53,6 @@ BlindingStatus BlindPSBT(PartiallySignedTransaction& psbt, std::map& proof, const CConfidentialAsset& conf_asset); bool VerifyBlindAssetProof(const uint256& asset, const std::vector& proof, const CConfidentialAsset& conf_asset); BlindProofResult VerifyBlindProofs(const PSBTOutput& o); +BlindProofResult VerifyBlindProofs(const PSBTInput& i); #endif //BITCOIN_BLINDPSBT_H From 4bacc852e9c7c12cfd1927df0aaa401d609123da Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 1 Sep 2022 13:56:52 -0400 Subject: [PATCH 4/8] rpc: Add input explicit value, asset, and proofs to decodepsbt --- src/rpc/rawtransaction.cpp | 39 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 4124b64f9e..3b7820f667 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1214,6 +1214,10 @@ static RPCHelpMan decodepsbt() {RPCResult::Type::STR_HEX, "", "hex-encoded witness data (if any)"}, }}, {RPCResult::Type::STR_HEX, "utxo_rangeproof", "The rangeproof for the UTXO"}, + {RPCResult::Type::NUM, "explicit_value", /*optional=*/true, "The explicit value for this input"}, + {RPCResult::Type::STR_HEX, "value_proof", /*optional=*/true, "The explicit value proof for this input"}, + {RPCResult::Type::STR_HEX, "explicit_asset", /*optional=*/true, "The explicit asset for this input"}, + {RPCResult::Type::STR_HEX, "asset_proof", /*optional=*/true, "The explicit asset proof for this input"}, {RPCResult::Type::OBJ_DYN, "unknown", "The unknown global fields", { {RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"}, @@ -1596,6 +1600,41 @@ static RPCHelpMan decodepsbt() in.pushKV("utxo_rangeproof", HexStr(input.m_utxo_rangeproof)); } + if (input.m_explicit_value.has_value()) { + in.pushKV("explicit_value", ValueFromAmount(*input.m_explicit_value)); + } + if (!input.m_value_proof.empty()) { + in.pushKV("value_proof", HexStr(input.m_value_proof)); + } + if (!input.m_explicit_asset.IsNull()) { + in.pushKV("explicit_asset", input.m_explicit_asset.GetHex()); + } + if (!input.m_asset_proof.empty()) { + in.pushKV("asset_proof", HexStr(input.m_asset_proof)); + } + + switch (VerifyBlindProofs(input)) { + case BlindProofResult::OK: + // all good + break; + case BlindProofResult::NOT_FULLY_BLINDED: + in.pushKV("status", "ERROR: Proofs provided for unblinded input"); + break; + case BlindProofResult::MISSING_VALUE_PROOF: + in.pushKV("status", "WARNING: has confidential and explicit values but no proof connecting them"); + break; + case BlindProofResult::MISSING_ASSET_PROOF: + in.pushKV("status", "WARNING: has confidential and explicit assets but no proof connecting them"); + break; + case BlindProofResult::INVALID_VALUE_PROOF: + in.pushKV("status", "ERROR: has invalid value proof, the value may be a lie!"); + break; + case BlindProofResult::INVALID_ASSET_PROOF: + in.pushKV("status", "ERROR: has invalid asset proof, the asset may be a lie!"); + break; + } + + // Proprietary if (!input.m_proprietary.empty()) { UniValue proprietary(UniValue::VARR); From 6291af43f90b6fdb27c5425e14bf2936aaef0b7c Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 1 Sep 2022 14:01:48 -0400 Subject: [PATCH 5/8] doc: Specify flag for blinding issuances --- doc/pset.mediawiki | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/pset.mediawiki b/doc/pset.mediawiki index 90c8ff73fd..d5f4680b77 100644 --- a/doc/pset.mediawiki +++ b/doc/pset.mediawiki @@ -295,6 +295,16 @@ The currently defined elements per-input proprietary types are as follows: | | 0 | 2 +|- +| Blinded Issuance Flag +| PSBT_ELEMENTS_IN_BLINDED_ISSUANCE = 0x15 +| None +| No key data +| <1 byte boolean> +| A boolean flag. 0x00 indicates the issuance should not be blinded, 0x01 indicates it should be. If not specified, assumed to be 0x01. Note that this does not indicate actual blinding status, but rather the expected blinding status prior to signing. +| +| 0 +| 2 |} The currently defined elements per-output proprietary types are as follows: From 9599661475827866b2da68452de4b9a7e7d4aa50 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 1 Sep 2022 14:09:32 -0400 Subject: [PATCH 6/8] pset: Implement de/ser of issuance needs blinded flag --- src/psbt.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/psbt.h b/src/psbt.h index 145410f3b0..585ca67da9 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -77,6 +77,7 @@ static constexpr uint8_t PSBT_ELEMENTS_IN_EXPLICIT_VALUE = 0x11; static constexpr uint8_t PSBT_ELEMENTS_IN_VALUE_PROOF = 0x12; static constexpr uint8_t PSBT_ELEMENTS_IN_EXPLICIT_ASSET = 0x13; static constexpr uint8_t PSBT_ELEMENTS_IN_ASSET_PROOF = 0x14; +static constexpr uint8_t PSBT_ELEMENTS_IN_BLINDED_ISSUANCE = 0x15; // Output types static constexpr uint8_t PSBT_OUT_REDEEMSCRIPT = 0x00; @@ -252,6 +253,7 @@ struct PSBTInput uint256 m_issuance_asset_entropy; std::vector m_blind_issuance_value_proof; std::vector m_blind_issuance_inflation_keys_proof; + std::optional m_blinded_issuance; // Peg-in std::variant m_peg_in_tx; @@ -501,6 +503,11 @@ struct PSBTInput SerializeToVector(s, CompactSizeWriter(PSBT_IN_PROPRIETARY), PSBT_ELEMENTS_ID, CompactSizeWriter(PSBT_ELEMENTS_IN_ASSET_PROOF)); s << m_asset_proof; } + + if (m_blinded_issuance.has_value()) { + SerializeToVector(s, CompactSizeWriter(PSBT_IN_PROPRIETARY), PSBT_ELEMENTS_ID, CompactSizeWriter(PSBT_ELEMENTS_IN_BLINDED_ISSUANCE)); + SerializeToVector(s, *m_blinded_issuance); + } } // Write proprietary things @@ -956,6 +963,18 @@ struct PSBTInput s >> m_value_proof; break; } + case PSBT_ELEMENTS_IN_BLINDED_ISSUANCE: + { + if (!key_lookup.emplace(key).second) { + throw std::ios_base::failure("Duplicate Key, issuance needs blinded flag is already provided"); + } else if (key.size() != 1) { + throw std::ios_base::failure("Input issuance needs blinded flag is more than one byte type"); + } + bool b; + UnserializeFromVector(s, b); + m_blinded_issuance = b; + break; + } default: { known = false; From cf870ed8d00ff513e6adfb815d276f9df37a7fd5 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 1 Sep 2022 14:11:37 -0400 Subject: [PATCH 7/8] rpc: Implement decodepsbt for issuance needs blinded flag --- src/rpc/rawtransaction.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 3b7820f667..01aed15ecf 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1218,6 +1218,7 @@ static RPCHelpMan decodepsbt() {RPCResult::Type::STR_HEX, "value_proof", /*optional=*/true, "The explicit value proof for this input"}, {RPCResult::Type::STR_HEX, "explicit_asset", /*optional=*/true, "The explicit asset for this input"}, {RPCResult::Type::STR_HEX, "asset_proof", /*optional=*/true, "The explicit asset proof for this input"}, + {RPCResult::Type::BOOL, "blinded_issuance", /*optional=*/true, "Whether the issuance should be blinded prior to signing"}, {RPCResult::Type::OBJ_DYN, "unknown", "The unknown global fields", { {RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"}, @@ -1613,6 +1614,10 @@ static RPCHelpMan decodepsbt() in.pushKV("asset_proof", HexStr(input.m_asset_proof)); } + if (input.m_blinded_issuance.has_value()) { + in.pushKV("blinded_issuance", *input.m_blinded_issuance); + } + switch (VerifyBlindProofs(input)) { case BlindProofResult::OK: // all good From 9ecbf38050ecb67939a111bf3e3cef43aee49720 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 1 Sep 2022 14:24:46 -0400 Subject: [PATCH 8/8] pset: Respect issuance needs blinded flag --- src/blindpsbt.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/blindpsbt.cpp b/src/blindpsbt.cpp index 8b964a9f17..6910d5ae85 100644 --- a/src/blindpsbt.cpp +++ b/src/blindpsbt.cpp @@ -415,7 +415,8 @@ BlindingStatus BlindPSBT(PartiallySignedTransaction& psbt, std::map