Skip to content

Commit 7f45b50

Browse files
authored
Merge pull request #85 from AnduroProject/fix-p2tsh-internal-key-
Fix p2tsh internal key
2 parents 9853593 + 2156243 commit 7f45b50

File tree

1 file changed

+48
-14
lines changed

1 file changed

+48
-14
lines changed

src/wallet/p2tsh_scriptpubkeyman.cpp

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,19 @@ extern "C" {
2020

2121
namespace 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+
2336
P2TSHScriptPubKeyMan::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

Comments
 (0)