@@ -21,6 +21,7 @@ static constexpr uint8_t PSBT_MAGIC_BYTES[5] = {'p', 's', 'b', 't', 0xff};
2121// Global types
2222static constexpr uint8_t PSBT_GLOBAL_UNSIGNED_TX = 0x00 ;
2323static constexpr uint8_t PSBT_GLOBAL_VERSION = 0xFB ;
24+ static constexpr uint8_t PSBT_GLOBAL_PROPRIETARY = 0xFC ;
2425
2526// Input types
2627static constexpr uint8_t PSBT_IN_NON_WITNESS_UTXO = 0x00 ;
@@ -32,11 +33,13 @@ static constexpr uint8_t PSBT_IN_WITNESSSCRIPT = 0x05;
3233static constexpr uint8_t PSBT_IN_BIP32_DERIVATION = 0x06 ;
3334static constexpr uint8_t PSBT_IN_SCRIPTSIG = 0x07 ;
3435static constexpr uint8_t PSBT_IN_SCRIPTWITNESS = 0x08 ;
36+ static constexpr uint8_t PSBT_IN_PROPRIETARY = 0xFC ;
3537
3638// Output types
3739static constexpr uint8_t PSBT_OUT_REDEEMSCRIPT = 0x00 ;
3840static constexpr uint8_t PSBT_OUT_WITNESSSCRIPT = 0x01 ;
3941static constexpr uint8_t PSBT_OUT_BIP32_DERIVATION = 0x02 ;
42+ static constexpr uint8_t PSBT_OUT_PROPRIETARY = 0xFC ;
4043
4144// The separator is 0x00. Reading this in means that the unserializer can interpret it
4245// as a 0 length key which indicates that this is the separator. The separator has no value.
@@ -49,6 +52,22 @@ const std::streamsize MAX_FILE_SIZE_PSBT = 100000000; // 100 MiB
4952// PSBT version number
5053static constexpr uint32_t PSBT_HIGHEST_VERSION = 0 ;
5154
55+ /* * A structure for PSBT proprietary types */
56+ struct PSBTProprietary
57+ {
58+ uint64_t subtype;
59+ std::vector<unsigned char > identifier;
60+ std::vector<unsigned char > key;
61+ std::vector<unsigned char > value;
62+
63+ bool operator <(const PSBTProprietary &b) const {
64+ return key < b.key ;
65+ }
66+ bool operator ==(const PSBTProprietary &b) const {
67+ return key == b.key ;
68+ }
69+ };
70+
5271/* * A structure for PSBTs which contain per-input information */
5372struct PSBTInput
5473{
@@ -61,6 +80,7 @@ struct PSBTInput
6180 std::map<CPubKey, KeyOriginInfo> hd_keypaths;
6281 std::map<CKeyID, SigPair> partial_sigs;
6382 std::map<std::vector<unsigned char >, std::vector<unsigned char >> unknown;
83+ std::set<PSBTProprietary> m_proprietary;
6484 std::optional<int > sighash_type;
6585
6686 bool IsNull () const ;
@@ -122,6 +142,12 @@ struct PSBTInput
122142 SerializeToVector (s, final_script_witness.stack );
123143 }
124144
145+ // Write proprietary things
146+ for (const auto & entry : m_proprietary) {
147+ s << entry.key ;
148+ s << entry.value ;
149+ }
150+
125151 // Write unknown things
126152 for (auto & entry : unknown) {
127153 s << entry.first ;
@@ -255,6 +281,20 @@ struct PSBTInput
255281 UnserializeFromVector (s, final_script_witness.stack );
256282 break ;
257283 }
284+ case PSBT_IN_PROPRIETARY:
285+ {
286+ PSBTProprietary this_prop;
287+ skey >> this_prop.identifier ;
288+ this_prop.subtype = ReadCompactSize (skey);
289+ this_prop.key = key;
290+
291+ if (m_proprietary.count (this_prop) > 0 ) {
292+ throw std::ios_base::failure (" Duplicate Key, proprietary key already found" );
293+ }
294+ s >> this_prop.value ;
295+ m_proprietary.insert (this_prop);
296+ break ;
297+ }
258298 // Unknown stuff
259299 default :
260300 if (unknown.count (key) > 0 ) {
@@ -286,6 +326,7 @@ struct PSBTOutput
286326 CScript witness_script;
287327 std::map<CPubKey, KeyOriginInfo> hd_keypaths;
288328 std::map<std::vector<unsigned char >, std::vector<unsigned char >> unknown;
329+ std::set<PSBTProprietary> m_proprietary;
289330
290331 bool IsNull () const ;
291332 void FillSignatureData (SignatureData& sigdata) const ;
@@ -310,6 +351,12 @@ struct PSBTOutput
310351 // Write any hd keypaths
311352 SerializeHDKeypaths (s, hd_keypaths, CompactSizeWriter (PSBT_OUT_BIP32_DERIVATION));
312353
354+ // Write proprietary things
355+ for (const auto & entry : m_proprietary) {
356+ s << entry.key ;
357+ s << entry.value ;
358+ }
359+
313360 // Write unknown things
314361 for (auto & entry : unknown) {
315362 s << entry.first ;
@@ -370,6 +417,20 @@ struct PSBTOutput
370417 DeserializeHDKeypaths (s, key, hd_keypaths);
371418 break ;
372419 }
420+ case PSBT_OUT_PROPRIETARY:
421+ {
422+ PSBTProprietary this_prop;
423+ skey >> this_prop.identifier ;
424+ this_prop.subtype = ReadCompactSize (skey);
425+ this_prop.key = key;
426+
427+ if (m_proprietary.count (this_prop) > 0 ) {
428+ throw std::ios_base::failure (" Duplicate Key, proprietary key already found" );
429+ }
430+ s >> this_prop.value ;
431+ m_proprietary.insert (this_prop);
432+ break ;
433+ }
373434 // Unknown stuff
374435 default : {
375436 if (unknown.count (key) > 0 ) {
@@ -403,6 +464,7 @@ struct PartiallySignedTransaction
403464 std::vector<PSBTOutput> outputs;
404465 std::map<std::vector<unsigned char >, std::vector<unsigned char >> unknown;
405466 std::optional<uint32_t > m_version;
467+ std::set<PSBTProprietary> m_proprietary;
406468
407469 bool IsNull () const ;
408470 uint32_t GetVersion () const ;
@@ -442,6 +504,12 @@ struct PartiallySignedTransaction
442504 SerializeToVector (s, *m_version);
443505 }
444506
507+ // Write proprietary things
508+ for (const auto & entry : m_proprietary) {
509+ s << entry.key ;
510+ s << entry.value ;
511+ }
512+
445513 // Write the unknown things
446514 for (auto & entry : unknown) {
447515 s << entry.first ;
@@ -529,6 +597,20 @@ struct PartiallySignedTransaction
529597 }
530598 break ;
531599 }
600+ case PSBT_GLOBAL_PROPRIETARY:
601+ {
602+ PSBTProprietary this_prop;
603+ skey >> this_prop.identifier ;
604+ this_prop.subtype = ReadCompactSize (skey);
605+ this_prop.key = key;
606+
607+ if (m_proprietary.count (this_prop) > 0 ) {
608+ throw std::ios_base::failure (" Duplicate Key, proprietary key already found" );
609+ }
610+ s >> this_prop.value ;
611+ m_proprietary.insert (this_prop);
612+ break ;
613+ }
532614 // Unknown stuff
533615 default : {
534616 if (unknown.count (key) > 0 ) {
0 commit comments