@@ -1834,9 +1834,13 @@ static bool ExecuteWitnessScript(const Span<const valtype>& stack_span, const CS
1834
1834
static bool VerifyTaprootCommitment (const std::vector<unsigned char >& control, const std::vector<unsigned char >& program, const CScript& script, uint256& tapleaf_hash)
1835
1835
{
1836
1836
const int path_len = (control.size () - TAPROOT_CONTROL_BASE_SIZE) / TAPROOT_CONTROL_NODE_SIZE;
1837
+ // ! The inner pubkey (x-only, so no Y coordinate parity).
1837
1838
const XOnlyPubKey p{uint256 (std::vector<unsigned char >(control.begin () + 1 , control.begin () + TAPROOT_CONTROL_BASE_SIZE))};
1839
+ // ! The output pubkey (taken from the scriptPubKey).
1838
1840
const XOnlyPubKey q{uint256 (program)};
1841
+ // Compute the tapleaf hash.
1839
1842
tapleaf_hash = (CHashWriter (HASHER_TAPLEAF) << uint8_t (control[0 ] & TAPROOT_LEAF_MASK) << script).GetSHA256 ();
1843
+ // Compute the Merkle root from the leaf and the provided path.
1840
1844
uint256 k = tapleaf_hash;
1841
1845
for (int i = 0 ; i < path_len; ++i) {
1842
1846
CHashWriter ss_branch{HASHER_TAPBRANCH};
@@ -1848,7 +1852,9 @@ static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, c
1848
1852
}
1849
1853
k = ss_branch.GetSHA256 ();
1850
1854
}
1855
+ // Compute the tweak from the Merkle root and the inner pubkey.
1851
1856
k = (CHashWriter (HASHER_TAPTWEAK) << MakeSpan (p) << k).GetSHA256 ();
1857
+ // Verify that the output pubkey matches the tweaked inner pubkey, after correcting for parity.
1852
1858
return q.CheckPayToContract (p, k, control[0 ] & 1 );
1853
1859
}
1854
1860
0 commit comments