@@ -20,6 +20,19 @@ extern "C" {
2020
2121namespace wallet {
2222
23+ // P2TSH Control Block Constants
24+ // The control byte includes leaf version (0xc0) with parity bit set to 1 (since no key-path)
25+ static constexpr uint8_t P2TSH_CONTROL_BYTE = 0xc1 ;
26+
27+ // Taproot control block header size (control byte + internal pubkey)
28+ static constexpr size_t TAPROOT_CB_HEADER_SIZE = 33 ; // 1 + 32
29+
30+ // P2TSH control block base size (just control byte, no internal pubkey)
31+ static constexpr size_t P2TSH_CB_BASE_SIZE = 1 ;
32+
33+ // Size of each merkle branch node
34+ static constexpr size_t P2TSH_CB_NODE_SIZE = 32 ;
35+
2336P2TSHScriptPubKeyMan::P2TSHScriptPubKeyMan (WalletStorage& storage)
2437 : ScriptPubKeyMan(storage)
2538{
@@ -156,7 +169,7 @@ util::Result<CTxDestination> P2TSHScriptPubKeyMan::GetNewP2TSHDestination(
156169 TaprootSpendData spend_data = builder.GetSpendData ();
157170 uint256 merkle_root = spend_data.merkle_root ;
158171
159- // ADD THIS DEBUG CODE:
172+ // Debug: Verify merkle root matches tapleaf hash for single-leaf tree
160173 uint256 tapleaf_hash_check = (HashWriter{HASHER_TAPLEAF}
161174 << uint8_t (TAPROOT_LEAF_TAPSCRIPT) // 0xc0
162175 << leaf_script
@@ -167,7 +180,6 @@ util::Result<CTxDestination> P2TSHScriptPubKeyMan::GetNewP2TSHDestination(
167180 WalletLogPrintf (" Merkle root: %s\n " , merkle_root.GetHex ());
168181 WalletLogPrintf (" Match: %s\n " , (merkle_root == tapleaf_hash_check) ? " YES - Single leaf" : " NO" );
169182 WalletLogPrintf (" ======================================\n " );
170- // END DEBUG CODE
171183
172184 // Convert CScript to vector<unsigned char> and create key pair
173185 std::vector<unsigned char > script_bytes (leaf_script.begin (), leaf_script.end ());
@@ -182,8 +194,33 @@ util::Result<CTxDestination> P2TSHScriptPubKeyMan::GetNewP2TSHDestination(
182194 if (control_it->second .empty ()) {
183195 return util::Error{Untranslated (" No control block found" )};
184196 }
197+
198+ // ============================================================
199+ // FIXED: Build P2TSH control block from Taproot control block
200+ // ============================================================
201+ // Taproot CB format: [control_byte(1)] [internal_pubkey(32)] [merkle_branch(N*32)]
202+ // P2TSH CB format: [control_byte(1)] [merkle_branch(N*32)]
203+ //
204+ // We use our own control byte (0xc1) and extract only the merkle branch,
205+ // discarding the internal pubkey since P2TSH has no key-path spending.
206+ // ============================================================
207+
208+ const std::vector<unsigned char >& taproot_cb = *control_it->second .begin ();
209+
185210 std::vector<unsigned char > control_block;
186- control_block.push_back (P2TSH_LEAF_TAPSCRIPT);
211+ control_block.push_back (P2TSH_CONTROL_BYTE); // 0xc1
212+
213+ // Extract merkle branch (skip Taproot's control byte + 32-byte internal pubkey)
214+ if (taproot_cb.size () > TAPROOT_CB_HEADER_SIZE) {
215+ control_block.insert (control_block.end (),
216+ taproot_cb.begin () + TAPROOT_CB_HEADER_SIZE,
217+ taproot_cb.end ());
218+ }
219+
220+ size_t merkle_branch_nodes = (control_block.size () - P2TSH_CB_BASE_SIZE) / P2TSH_CB_NODE_SIZE;
221+ WalletLogPrintf (" P2TSH: Control block size: %zu bytes (merkle branch nodes: %zu)\n " ,
222+ control_block.size (), merkle_branch_nodes);
223+ WalletLogPrintf (" P2TSH: Control block hex: %s\n " , HexStr (control_block));
187224
188225 // Create metadata
189226 P2TSHKeyMetadata metadata;
@@ -409,11 +446,11 @@ bool P2TSHScriptPubKeyMan::SignP2TSHInput(
409446 // For P2TSH, use SigVersion::TAPSCRIPT which will compute the tapleaf hash
410447 // from the script using leaf version 0xc1 (P2TSH_LEAF_TAPSCRIPT)
411448
412- // ADD THESE DEBUG LINES:
449+ // Debug script information
413450 WalletLogPrintf (" P2TSH: Leaf script size: %zu bytes\n " , metadata.leaf_script .size ());
414451 WalletLogPrintf (" P2TSH: Leaf script hex: %s\n " , HexStr (metadata.leaf_script ));
415452
416- // CRITICAL: Check if script starts with correct opcodes
453+ // Check script sizes based on signature type
417454 if (metadata.sig_type == P2TSHSignatureType::HYBRID) {
418455 WalletLogPrintf (" P2TSH: HYBRID SCRIPT CHECK:\n " );
419456 WalletLogPrintf (" P2TSH: Expected size: 70 bytes\n " );
@@ -445,12 +482,11 @@ bool P2TSHScriptPubKeyMan::SignP2TSHInput(
445482 WalletLogPrintf (" P2TSH: WARNING - SLH_DSA_ONLY signature type but script size is %zu (expected 34)!\n " ,
446483 metadata.leaf_script .size ());
447484 }
448- // END DEBUG LINES
449485
450486
451487 // Compute tapleaf hash for logging/verification
452488 uint256 tapleaf_hash = (HashWriter{HASHER_TAPLEAF}
453- << uint8_t (TAPROOT_LEAF_TAPSCRIPT) // 0xc0 ✅ CORRECT!
489+ << uint8_t (TAPROOT_LEAF_TAPSCRIPT) // 0xc0
454490 << metadata.leaf_script
455491 ).GetSHA256 ();
456492
@@ -477,11 +513,10 @@ bool P2TSHScriptPubKeyMan::SignP2TSHInput(
477513 if (prev_tx && txin.prevout .n < prev_tx->tx ->vout .size ()) {
478514 spent_outputs.push_back (prev_tx->tx ->vout [txin.prevout .n ]);
479515 } else {
480- // If we can't find the output, add a dummy one
481- // This might cause signing to fail
516+ // If we can't find the output, fail
482517 WalletLogPrintf (" P2TSH: ERROR - Cannot find spent output for input %zu (txid: %s, vout: %u)\n " ,
483518 i, txin.prevout .hash .ToString (), txin.prevout .n );
484- return false ; // ✅ FAIL instead of using dummy!
519+ return false ;
485520 }
486521 }
487522 }
@@ -495,7 +530,7 @@ bool P2TSHScriptPubKeyMan::SignP2TSHInput(
495530 execdata.m_codeseparator_pos_init = true ;
496531 execdata.m_codeseparator_pos = 0xFFFFFFFF ; // No OP_CODESEPARATOR
497532 execdata.m_tapleaf_hash_init = true ;
498- execdata.m_tapleaf_hash = tapleaf_hash; // ← CRITICAL!
533+ execdata.m_tapleaf_hash = tapleaf_hash;
499534
500535 int actual_sighash_type = sighash_type;
501536 if (metadata.sig_type == P2TSHSignatureType::HYBRID) {
@@ -806,8 +841,7 @@ bool P2TSHScriptPubKeyMan::SignSchnorr(
806841
807842 secp256k1_context_destroy (secp_ctx);
808843
809- // ✅ DON'T append sighash type - 64 bytes = SIGHASH_DEFAULT (implied)
810- // signature.push_back(SIGHASH_DEFAULT); // REMOVE THIS LINE
844+ // DON'T append sighash type - 64 bytes = SIGHASH_DEFAULT (implied)
811845
812846 WalletLogPrintf (" P2TSH: Created Schnorr signature (%zu bytes)\n " , signature.size ());
813847 return true ;
@@ -829,7 +863,7 @@ bool P2TSHScriptPubKeyMan::SignSLHDSA(
829863 size_t siglen = SLH_DSA_SHAKE_128S_SIGNATURE_SIZE;
830864 int result = slh_dsa_shake_128s_sign (
831865 signature.data (),
832- &siglen, // Add this parameter
866+ &siglen,
833867 sighash.begin (),
834868 32 ,
835869 privkey.data ()
0 commit comments