From fc3458e71df1262c1321152e75e01c2ca2448207 Mon Sep 17 00:00:00 2001 From: Leonardo Comandini Date: Tue, 23 Apr 2024 09:35:59 +0200 Subject: [PATCH 1/4] doc: pset: add input and output asset blinding factor --- doc/pset.mediawiki | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/doc/pset.mediawiki b/doc/pset.mediawiki index d5f4680b77..37c35795b6 100644 --- a/doc/pset.mediawiki +++ b/doc/pset.mediawiki @@ -305,6 +305,16 @@ The currently defined elements per-input proprietary types are as follows: | | 0 | 2 +|- +| Asset Blinding Factor +| PSBT_ELEMENTS_IN_ASSET_BLINDING_FACTOR = 0x16 +| None +| No key data +| <256 bit uint> +| The 32 byte asset blinding factor for the input being spent. +| +| 0 +| 2 |} The currently defined elements per-output proprietary types are as follows: @@ -408,7 +418,8 @@ The currently defined elements per-output proprietary types are as follows: | An explicit value rangeproof that proves that the value commitment in PSBT_ELEMENTS_OUT_VALUE_COMMITMENT matches the explicit value in PSBT_OUT_VALUE. If provided, PSBT_ELEMENTS_OUT_VALUE_COMMITMENT must be provided too. | | 0 -| 2|- +| 2 +|- | Blind Asset Proof | PSBT_ELEMENTS_OUT_BLIND_ASSET_PROOF = 0x0a | None @@ -418,6 +429,16 @@ The currently defined elements per-output proprietary types are as follows: | | 0 | 2 +|- +| Asset Blinding Factor +| PSBT_ELEMENTS_OUT_ASSET_BLINDING_FACTOR = 0x0b +| None +| No key data +| <256 bit uint> +| The 32 byte asset blinding factor of this output. +| +| 0 +| 2 |} The PSET Magic Bytes are 0x70736574 From 7f94ff11f5999a33f8fbf20122c670e3674762dc Mon Sep 17 00:00:00 2001 From: Leonardo Comandini Date: Tue, 23 Apr 2024 10:04:43 +0200 Subject: [PATCH 2/4] pset: (de)serialize input and output asset blinding factor --- src/psbt.h | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/psbt.h b/src/psbt.h index fbcbdb2057..98ed820f16 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -85,6 +85,7 @@ 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; +static constexpr uint8_t PSBT_ELEMENTS_IN_ASSET_BLINDING_FACTOR = 0x16; // Output types static constexpr uint8_t PSBT_OUT_REDEEMSCRIPT = 0x00; @@ -104,6 +105,7 @@ static constexpr uint8_t PSBT_ELEMENTS_OUT_ECDH_PUBKEY = 0x07; static constexpr uint8_t PSBT_ELEMENTS_OUT_BLINDER_INDEX = 0x08; static constexpr uint8_t PSBT_ELEMENTS_OUT_BLIND_VALUE_PROOF = 0x09; static constexpr uint8_t PSBT_ELEMENTS_OUT_BLIND_ASSET_PROOF = 0x0a; +static constexpr uint8_t PSBT_ELEMENTS_OUT_ASSET_BLINDING_FACTOR = 0x0b; // Proprietary type identifier string static const std::vector PSBT_ELEMENTS_ID = {'p', 's', 'e', 't'}; @@ -280,6 +282,7 @@ struct PSBTInput std::vector m_value_proof; uint256 m_explicit_asset; std::vector m_asset_proof; + std::optional m_asset_blinding_factor{std::nullopt}; bool IsNull() const; void FillSignatureData(SignatureData& sigdata) const; @@ -543,6 +546,12 @@ struct PSBTInput SerializeToVector(s, CompactSizeWriter(PSBT_IN_PROPRIETARY), PSBT_ELEMENTS_ID, CompactSizeWriter(PSBT_ELEMENTS_IN_BLINDED_ISSUANCE)); SerializeToVector(s, *m_blinded_issuance); } + + // Asset blinding factor + if (m_asset_blinding_factor.has_value()) { + SerializeToVector(s, CompactSizeWriter(PSBT_IN_PROPRIETARY), PSBT_ELEMENTS_ID, CompactSizeWriter(PSBT_ELEMENTS_IN_ASSET_BLINDING_FACTOR)); + SerializeToVector(s, m_asset_blinding_factor.value()); + } } // Write proprietary things @@ -1096,6 +1105,18 @@ struct PSBTInput m_blinded_issuance = b; break; } + case PSBT_ELEMENTS_IN_ASSET_BLINDING_FACTOR: + { + if (m_asset_blinding_factor.has_value()) { + throw std::ios_base::failure("Duplicate Key, input asset blinding factor is already provided"); + } else if (subkey_len != 1) { + throw std::ios_base::failure("Input asset blinding factor is more than one byte type"); + } + uint256 u; + UnserializeFromVector(s, u); + m_asset_blinding_factor = u; + break; + } default: { known = false; @@ -1185,6 +1206,7 @@ struct PSBTOutput std::optional m_blinder_index{std::nullopt}; std::vector m_blind_value_proof; std::vector m_blind_asset_proof; + std::optional m_asset_blinding_factor{std::nullopt}; bool IsNull() const; void FillSignatureData(SignatureData& sigdata) const; @@ -1282,6 +1304,12 @@ struct PSBTOutput SerializeToVector(s, CompactSizeWriter(PSBT_OUT_PROPRIETARY), PSBT_ELEMENTS_ID, CompactSizeWriter(PSBT_ELEMENTS_OUT_BLIND_ASSET_PROOF)); s << m_blind_asset_proof; } + + // Asset blinding factor + if (m_asset_blinding_factor.has_value()) { + SerializeToVector(s, CompactSizeWriter(PSBT_OUT_PROPRIETARY), PSBT_ELEMENTS_ID, CompactSizeWriter(PSBT_ELEMENTS_OUT_ASSET_BLINDING_FACTOR)); + SerializeToVector(s, m_asset_blinding_factor.value()); + } } // Write proprietary things @@ -1488,6 +1516,18 @@ struct PSBTOutput s >> m_blind_asset_proof; break; } + case PSBT_ELEMENTS_OUT_ASSET_BLINDING_FACTOR: + { + if (m_asset_blinding_factor.has_value()) { + throw std::ios_base::failure("Duplicate Key, output asset blinding factor is already provided"); + } else if (subkey_len != 1) { + throw std::ios_base::failure("Output asset blinding factor is more than one byte type"); + } + uint256 u; + UnserializeFromVector(s, u); + m_asset_blinding_factor = u; + break; + } default: { known = false; From e919a518e9607d04fca6a53475ef058c32160ee9 Mon Sep 17 00:00:00 2001 From: Leonardo Comandini Date: Tue, 23 Apr 2024 10:05:38 +0200 Subject: [PATCH 3/4] rpc: decodepsbt: return input and output asset blinding factor --- src/rpc/rawtransaction.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 1881bb12f7..e095072025 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1272,6 +1272,7 @@ static RPCHelpMan decodepsbt() {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::STR_HEX, "asset_blinder", /*optional=*/true, "The asset blinding factor for this input"}, {RPCResult::Type::OBJ_DYN, "ripemd160_preimages", /*optional=*/ true, "", { {RPCResult::Type::STR, "hash", "The hash and preimage that corresponds to it."}, @@ -1342,6 +1343,7 @@ static RPCHelpMan decodepsbt() {RPCResult::Type::STR_HEX, "blinding_pubkey", "The blinding pubkey for the output"}, {RPCResult::Type::STR_HEX, "blind_value_proof", "Explicit value rangeproof that proves the value commitment matches the value"}, {RPCResult::Type::STR_HEX, "blind_asset_proof", "Assert surjection proof that proves the assert commitment matches the asset"}, + {RPCResult::Type::STR_HEX, "asset_blinder", /*optional=*/true, "The asset blinding factor for the output"}, {RPCResult::Type::STR, "status", "information about how the output has been blinded, if available"}, {RPCResult::Type::OBJ_DYN, "unknown", /*optional=*/true, "The unknown global fields", { @@ -1687,6 +1689,10 @@ static RPCHelpMan decodepsbt() in.pushKV("blinded_issuance", *input.m_blinded_issuance); } + if (input.m_asset_blinding_factor.has_value()) { + in.pushKV("asset_blinder", input.m_asset_blinding_factor.value().GetHex()); + } + switch (VerifyBlindProofs(input)) { case BlindProofResult::OK: // all good @@ -1864,6 +1870,11 @@ static RPCHelpMan decodepsbt() out.pushKV("blind_asset_proof", HexStr(output.m_blind_asset_proof)); } + // Asset blinding factor + if (output.m_asset_blinding_factor.has_value()) { + out.pushKV("asset_blinder", output.m_asset_blinding_factor.value().GetHex()); + } + switch (VerifyBlindProofs(output)) { case BlindProofResult::OK: // all good From ee082284a9b5cdf0a144b887c3e78325b6ef31f0 Mon Sep 17 00:00:00 2001 From: Leonardo Comandini Date: Tue, 23 Apr 2024 15:59:00 +0200 Subject: [PATCH 4/4] test: pset: decodepsbt returns asset blinding factors --- test/functional/rpc_psbt.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py index 8aff333b42..18a7800295 100755 --- a/test/functional/rpc_psbt.py +++ b/test/functional/rpc_psbt.py @@ -853,6 +853,7 @@ def pset_confidential_proofs(self): INPUT_MISSING_VALUE_PROOF = "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" INPUT_MISSING_ASSET = "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" INPUT_MISSING_ASSET_PROOF = "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" + INPUT_OUTPUT_ABF = "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" # Check warnings for PSETs stats = [output.get("status") for output in self.nodes[0].decodepsbt(UNBLINDED)["outputs"]] @@ -930,6 +931,11 @@ def pset_confidential_proofs(self): assert_raises_rpc_error(-22, "TX decode failed Input explicit asset and asset proof must be provided together", self.nodes[0].decodepsbt, INPUT_MISSING_ASSET) assert_raises_rpc_error(-22, "TX decode failed Input explicit asset and asset proof must be provided together", self.nodes[0].decodepsbt, INPUT_MISSING_ASSET_PROOF) + # PSETs can have input and output asset blinding factors + decoded = self.nodes[0].decodepsbt(INPUT_OUTPUT_ABF) + assert decoded["inputs"][0]["asset_blinder"] == "3311111111111111111111111111111111111111111111111111111111111111" + assert decoded["outputs"][0]["asset_blinder"] == "3311111111111111111111111111111111111111111111111111111111111111" + # The fully-blinded (with proofs) PSET will combine with the blinded one, # and will copy the blinded data assert_equal (self.nodes[0].combinepsbt([UNBLINDED, BLINDED]), BLINDED)