Skip to content

Commit 05e2cc9

Browse files
committed
Implement de/ser of PSBT's Taproot fields
1 parent d557eff commit 05e2cc9

File tree

1 file changed

+257
-0
lines changed

1 file changed

+257
-0
lines changed

src/psbt.h

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,21 @@ static constexpr uint8_t PSBT_IN_RIPEMD160 = 0x0A;
4040
static constexpr uint8_t PSBT_IN_SHA256 = 0x0B;
4141
static constexpr uint8_t PSBT_IN_HASH160 = 0x0C;
4242
static constexpr uint8_t PSBT_IN_HASH256 = 0x0D;
43+
static constexpr uint8_t PSBT_IN_TAP_KEY_SIG = 0x13;
44+
static constexpr uint8_t PSBT_IN_TAP_SCRIPT_SIG = 0x14;
45+
static constexpr uint8_t PSBT_IN_TAP_LEAF_SCRIPT = 0x15;
46+
static constexpr uint8_t PSBT_IN_TAP_BIP32_DERIVATION = 0x16;
47+
static constexpr uint8_t PSBT_IN_TAP_INTERNAL_KEY = 0x17;
48+
static constexpr uint8_t PSBT_IN_TAP_MERKLE_ROOT = 0x18;
4349
static constexpr uint8_t PSBT_IN_PROPRIETARY = 0xFC;
4450

4551
// Output types
4652
static constexpr uint8_t PSBT_OUT_REDEEMSCRIPT = 0x00;
4753
static constexpr uint8_t PSBT_OUT_WITNESSSCRIPT = 0x01;
4854
static constexpr uint8_t PSBT_OUT_BIP32_DERIVATION = 0x02;
55+
static constexpr uint8_t PSBT_OUT_TAP_INTERNAL_KEY = 0x05;
56+
static constexpr uint8_t PSBT_OUT_TAP_TREE = 0x06;
57+
static constexpr uint8_t PSBT_OUT_TAP_BIP32_DERIVATION = 0x07;
4958
static constexpr uint8_t PSBT_OUT_PROPRIETARY = 0xFC;
5059

5160
// The separator is 0x00. Reading this in means that the unserializer can interpret it
@@ -193,6 +202,15 @@ struct PSBTInput
193202
std::map<uint256, std::vector<unsigned char>> sha256_preimages;
194203
std::map<uint160, std::vector<unsigned char>> hash160_preimages;
195204
std::map<uint256, std::vector<unsigned char>> hash256_preimages;
205+
206+
// Taproot fields
207+
std::vector<unsigned char> m_tap_key_sig;
208+
std::map<std::pair<XOnlyPubKey, uint256>, std::vector<unsigned char>> m_tap_script_sigs;
209+
std::map<std::pair<CScript, int>, std::set<std::vector<unsigned char>, ShortestVectorFirstComparator>> m_tap_scripts;
210+
std::map<XOnlyPubKey, std::pair<std::set<uint256>, KeyOriginInfo>> m_tap_bip32_paths;
211+
XOnlyPubKey m_tap_internal_key;
212+
uint256 m_tap_merkle_root;
213+
196214
std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown;
197215
std::set<PSBTProprietary> m_proprietary;
198216
std::optional<int> sighash_type;
@@ -267,6 +285,53 @@ struct PSBTInput
267285
SerializeToVector(s, CompactSizeWriter(PSBT_IN_HASH256), Span{hash});
268286
s << preimage;
269287
}
288+
289+
// Write taproot key sig
290+
if (!m_tap_key_sig.empty()) {
291+
SerializeToVector(s, PSBT_IN_TAP_KEY_SIG);
292+
s << m_tap_key_sig;
293+
}
294+
295+
// Write taproot script sigs
296+
for (const auto& [pubkey_leaf, sig] : m_tap_script_sigs) {
297+
const auto& [xonly, leaf_hash] = pubkey_leaf;
298+
SerializeToVector(s, PSBT_IN_TAP_SCRIPT_SIG, xonly, leaf_hash);
299+
s << sig;
300+
}
301+
302+
// Write taproot leaf scripts
303+
for (const auto& [leaf, control_blocks] : m_tap_scripts) {
304+
const auto& [script, leaf_ver] = leaf;
305+
for (const auto& control_block : control_blocks) {
306+
SerializeToVector(s, PSBT_IN_TAP_LEAF_SCRIPT, Span{control_block});
307+
std::vector<unsigned char> value_v(script.begin(), script.end());
308+
value_v.push_back((uint8_t)leaf_ver);
309+
s << value_v;
310+
}
311+
}
312+
313+
// Write taproot bip32 keypaths
314+
for (const auto& [xonly, leaf_origin] : m_tap_bip32_paths) {
315+
const auto& [leaf_hashes, origin] = leaf_origin;
316+
SerializeToVector(s, PSBT_IN_TAP_BIP32_DERIVATION, xonly);
317+
std::vector<unsigned char> value;
318+
CVectorWriter s_value(s.GetType(), s.GetVersion(), value, 0);
319+
s_value << leaf_hashes;
320+
SerializeKeyOrigin(s_value, origin);
321+
s << value;
322+
}
323+
324+
// Write taproot internal key
325+
if (!m_tap_internal_key.IsNull()) {
326+
SerializeToVector(s, PSBT_IN_TAP_INTERNAL_KEY);
327+
s << ToByteVector(m_tap_internal_key);
328+
}
329+
330+
// Write taproot merkle root
331+
if (!m_tap_merkle_root.IsNull()) {
332+
SerializeToVector(s, PSBT_IN_TAP_MERKLE_ROOT);
333+
SerializeToVector(s, m_tap_merkle_root);
334+
}
270335
}
271336

272337
// Write script sig
@@ -503,6 +568,103 @@ struct PSBTInput
503568
hash256_preimages.emplace(hash, std::move(preimage));
504569
break;
505570
}
571+
case PSBT_IN_TAP_KEY_SIG:
572+
{
573+
if (!key_lookup.emplace(key).second) {
574+
throw std::ios_base::failure("Duplicate Key, input Taproot key signature already provided");
575+
} else if (key.size() != 1) {
576+
throw std::ios_base::failure("Input Taproot key signature key is more than one byte type");
577+
}
578+
s >> m_tap_key_sig;
579+
if (m_tap_key_sig.size() < 64) {
580+
throw std::ios_base::failure("Input Taproot key path signature is shorter than 64 bytes");
581+
} else if (m_tap_key_sig.size() > 65) {
582+
throw std::ios_base::failure("Input Taproot key path signature is longer than 65 bytes");
583+
}
584+
break;
585+
}
586+
case PSBT_IN_TAP_SCRIPT_SIG:
587+
{
588+
if (!key_lookup.emplace(key).second) {
589+
throw std::ios_base::failure("Duplicate Key, input Taproot script signature already provided");
590+
} else if (key.size() != 65) {
591+
throw std::ios_base::failure("Input Taproot script signature key is not 65 bytes");
592+
}
593+
SpanReader s_key(s.GetType(), s.GetVersion(), Span{key}.subspan(1));
594+
XOnlyPubKey xonly;
595+
uint256 hash;
596+
s_key >> xonly;
597+
s_key >> hash;
598+
std::vector<unsigned char> sig;
599+
s >> sig;
600+
if (sig.size() < 64) {
601+
throw std::ios_base::failure("Input Taproot script path signature is shorter than 64 bytes");
602+
} else if (sig.size() > 65) {
603+
throw std::ios_base::failure("Input Taproot script path signature is longer than 65 bytes");
604+
}
605+
m_tap_script_sigs.emplace(std::make_pair(xonly, hash), sig);
606+
break;
607+
}
608+
case PSBT_IN_TAP_LEAF_SCRIPT:
609+
{
610+
if (!key_lookup.emplace(key).second) {
611+
throw std::ios_base::failure("Duplicate Key, input Taproot leaf script already provided");
612+
} else if (key.size() < 34) {
613+
throw std::ios_base::failure("Taproot leaf script key is not at least 34 bytes");
614+
} else if ((key.size() - 2) % 32 != 0) {
615+
throw std::ios_base::failure("Input Taproot leaf script key's control block size is not valid");
616+
}
617+
std::vector<unsigned char> script_v;
618+
s >> script_v;
619+
if (script_v.empty()) {
620+
throw std::ios_base::failure("Input Taproot leaf script must be at least 1 byte");
621+
}
622+
uint8_t leaf_ver = script_v.back();
623+
script_v.pop_back();
624+
const auto leaf_script = std::make_pair(CScript(script_v.begin(), script_v.end()), (int)leaf_ver);
625+
m_tap_scripts[leaf_script].insert(std::vector<unsigned char>(key.begin() + 1, key.end()));
626+
break;
627+
}
628+
case PSBT_IN_TAP_BIP32_DERIVATION:
629+
{
630+
if (!key_lookup.emplace(key).second) {
631+
throw std::ios_base::failure("Duplicate Key, input Taproot BIP32 keypath already provided");
632+
} else if (key.size() != 33) {
633+
throw std::ios_base::failure("Input Taproot BIP32 keypath key is not at 33 bytes");
634+
}
635+
SpanReader s_key(s.GetType(), s.GetVersion(), Span{key}.subspan(1));
636+
XOnlyPubKey xonly;
637+
s_key >> xonly;
638+
std::set<uint256> leaf_hashes;
639+
uint64_t value_len = ReadCompactSize(s);
640+
size_t before_hashes = s.size();
641+
s >> leaf_hashes;
642+
size_t after_hashes = s.size();
643+
size_t hashes_len = before_hashes - after_hashes;
644+
size_t origin_len = value_len - hashes_len;
645+
m_tap_bip32_paths.emplace(xonly, std::make_pair(leaf_hashes, DeserializeKeyOrigin(s, origin_len)));
646+
break;
647+
}
648+
case PSBT_IN_TAP_INTERNAL_KEY:
649+
{
650+
if (!key_lookup.emplace(key).second) {
651+
throw std::ios_base::failure("Duplicate Key, input Taproot internal key already provided");
652+
} else if (key.size() != 1) {
653+
throw std::ios_base::failure("Input Taproot internal key key is more than one byte type");
654+
}
655+
UnserializeFromVector(s, m_tap_internal_key);
656+
break;
657+
}
658+
case PSBT_IN_TAP_MERKLE_ROOT:
659+
{
660+
if (!key_lookup.emplace(key).second) {
661+
throw std::ios_base::failure("Duplicate Key, input Taproot merkle root already provided");
662+
} else if (key.size() != 1) {
663+
throw std::ios_base::failure("Input Taproot merkle root key is more than one byte type");
664+
}
665+
UnserializeFromVector(s, m_tap_merkle_root);
666+
break;
667+
}
506668
case PSBT_IN_PROPRIETARY:
507669
{
508670
PSBTProprietary this_prop;
@@ -547,6 +709,9 @@ struct PSBTOutput
547709
CScript redeem_script;
548710
CScript witness_script;
549711
std::map<CPubKey, KeyOriginInfo> hd_keypaths;
712+
XOnlyPubKey m_tap_internal_key;
713+
std::optional<TaprootBuilder> m_tap_tree;
714+
std::map<XOnlyPubKey, std::pair<std::set<uint256>, KeyOriginInfo>> m_tap_bip32_paths;
550715
std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown;
551716
std::set<PSBTProprietary> m_proprietary;
552717

@@ -579,6 +744,40 @@ struct PSBTOutput
579744
s << entry.value;
580745
}
581746

747+
// Write taproot internal key
748+
if (!m_tap_internal_key.IsNull()) {
749+
SerializeToVector(s, PSBT_OUT_TAP_INTERNAL_KEY);
750+
s << ToByteVector(m_tap_internal_key);
751+
}
752+
753+
// Write taproot tree
754+
if (m_tap_tree.has_value()) {
755+
SerializeToVector(s, PSBT_OUT_TAP_TREE);
756+
std::vector<unsigned char> value;
757+
CVectorWriter s_value(s.GetType(), s.GetVersion(), value, 0);
758+
const auto& tuples = m_tap_tree->GetTreeTuples();
759+
for (const auto& tuple : tuples) {
760+
uint8_t depth = std::get<0>(tuple);
761+
uint8_t leaf_ver = std::get<1>(tuple);
762+
CScript script = std::get<2>(tuple);
763+
s_value << depth;
764+
s_value << leaf_ver;
765+
s_value << script;
766+
}
767+
s << value;
768+
}
769+
770+
// Write taproot bip32 keypaths
771+
for (const auto& [xonly, leaf] : m_tap_bip32_paths) {
772+
const auto& [leaf_hashes, origin] = leaf;
773+
SerializeToVector(s, PSBT_OUT_TAP_BIP32_DERIVATION, xonly);
774+
std::vector<unsigned char> value;
775+
CVectorWriter s_value(s.GetType(), s.GetVersion(), value, 0);
776+
s_value << leaf_hashes;
777+
SerializeKeyOrigin(s_value, origin);
778+
s << value;
779+
}
780+
582781
// Write unknown things
583782
for (auto& entry : unknown) {
584783
s << entry.first;
@@ -639,6 +838,59 @@ struct PSBTOutput
639838
DeserializeHDKeypaths(s, key, hd_keypaths);
640839
break;
641840
}
841+
case PSBT_OUT_TAP_INTERNAL_KEY:
842+
{
843+
if (!key_lookup.emplace(key).second) {
844+
throw std::ios_base::failure("Duplicate Key, output Taproot internal key already provided");
845+
} else if (key.size() != 1) {
846+
throw std::ios_base::failure("Output Taproot internal key key is more than one byte type");
847+
}
848+
UnserializeFromVector(s, m_tap_internal_key);
849+
break;
850+
}
851+
case PSBT_OUT_TAP_TREE:
852+
{
853+
if (!key_lookup.emplace(key).second) {
854+
throw std::ios_base::failure("Duplicate Key, output Taproot tree already provided");
855+
} else if (key.size() != 1) {
856+
throw std::ios_base::failure("Output Taproot tree key is more than one byte type");
857+
}
858+
m_tap_tree.emplace();
859+
std::vector<unsigned char> tree_v;
860+
s >> tree_v;
861+
SpanReader s_tree(s.GetType(), s.GetVersion(), tree_v);
862+
while (!s_tree.empty()) {
863+
uint8_t depth;
864+
uint8_t leaf_ver;
865+
CScript script;
866+
s_tree >> depth;
867+
s_tree >> leaf_ver;
868+
s_tree >> script;
869+
m_tap_tree->Add((int)depth, script, (int)leaf_ver, true /* track */);
870+
}
871+
if (!m_tap_tree->IsComplete()) {
872+
throw std::ios_base::failure("Output Taproot tree is malformed");
873+
}
874+
break;
875+
}
876+
case PSBT_OUT_TAP_BIP32_DERIVATION:
877+
{
878+
if (!key_lookup.emplace(key).second) {
879+
throw std::ios_base::failure("Duplicate Key, output Taproot BIP32 keypath already provided");
880+
} else if (key.size() != 33) {
881+
throw std::ios_base::failure("Output Taproot BIP32 keypath key is not at 33 bytes");
882+
}
883+
XOnlyPubKey xonly(uint256({key.begin() + 1, key.begin() + 33}));
884+
std::set<uint256> leaf_hashes;
885+
uint64_t value_len = ReadCompactSize(s);
886+
size_t before_hashes = s.size();
887+
s >> leaf_hashes;
888+
size_t after_hashes = s.size();
889+
size_t hashes_len = before_hashes - after_hashes;
890+
size_t origin_len = value_len - hashes_len;
891+
m_tap_bip32_paths.emplace(xonly, std::make_pair(leaf_hashes, DeserializeKeyOrigin(s, origin_len)));
892+
break;
893+
}
642894
case PSBT_OUT_PROPRIETARY:
643895
{
644896
PSBTProprietary this_prop;
@@ -667,6 +919,11 @@ struct PSBTOutput
667919
}
668920
}
669921

922+
// Finalize m_tap_tree so that all of the computed things are computed
923+
if (m_tap_tree.has_value() && m_tap_tree->IsComplete() && m_tap_internal_key.IsFullyValid()) {
924+
m_tap_tree->Finalize(m_tap_internal_key);
925+
}
926+
670927
if (!found_sep) {
671928
throw std::ios_base::failure("Separator is missing at the end of an output map");
672929
}

0 commit comments

Comments
 (0)