Bitcoin Forum
August 25, 2026, 07:31:56 AM *
News: Latest Bitcoin Core release: 31.1 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: Does the bitcoin validate the taproot script path commitment?  (Read 138 times)
Hashblock (OP)
Newbie
*
Offline

Activity: 3
Merit: 0


View Profile
August 10, 2026, 05:31:37 PM
 #1

Hello guys, I’m new here. But not new to bitcoin actually, while trying to understand one specific part of taproot transactions validation. I had so many thoughts and questions.
Assuming a taproot output was created with internal key p and a script tree with merkle root m. Output is:
Q= p+ H_TapTweak( p || m) G
When sending the script path, the witness provides the script, stack elements and a control block.
Now my question is how exactly does the bitcoin node proves that this revealed script actually belongs to the taproot output being spent?

athanred
Member
**
Offline

Activity: 100
Merit: 158


View Profile
August 11, 2026, 01:29:37 AM
Merited by Cricktor (1)
 #2

Quote
how exactly does the bitcoin node proves that this revealed script actually belongs to the taproot output being spent?
By hashing a given TapScript, and checking, if secp256k1 point addition matches.

Let's say, that you have some public key:
Code:
P=02BB0CC84DB7B318CB9F3521B809530440DE0870F8E53D075298D06B10018162B8
And now, let's say, that you have some message, which you want to commit into it:
Code:
SHA-256("message")=ab530a13e45914982b79f9b7e3fba994cfd1f3fb22f71cea1afbf02b460c6d1d
Now, both things can be combined under some new public key, exactly as you described:
Code:
Q=P+H_TapTweak(p||m)G
P=02BB0CC84DB7B318CB9F3521B809530440DE0870F8E53D075298D06B10018162B8
p=bb0cc84db7b318cb9f3521b809530440de0870f8e53d075298d06b10018162b8
m=ab530a13e45914982b79f9b7e3fba994cfd1f3fb22f71cea1afbf02b460c6d1d
SHA-256("TapTweak")=e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9
H_TapTweak(p||m)=SHA-256(e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9e80fe1639c9ca050e3af1b39c143c63e429cbceb15d940fbb5c5a1f4af57c5e9bb0cc84db7b318cb9f3521b809530440de0870f8e53d075298d06b10018162b8ab530a13e45914982b79f9b7e3fba994cfd1f3fb22f71cea1afbf02b460c6d1d)=9409ba4775979349c29ab664fa65dff67458b02ef726cbf8257c66257a837a7d
H_TapTweak(p||m)*G=028AF5531F8100ACD57F3D49C47E3DCD6002439BED59ADAAB83ECEDB82B62D3367
Q=02BB0CC84DB7B318CB9F3521B809530440DE0870F8E53D075298D06B10018162B8+028AF5531F8100ACD57F3D49C47E3DCD6002439BED59ADAAB83ECEDB82B62D3367
Q=037D9E93308E6105308D46B3A7912844FBD0925F920381501C19FC21716B6B4ADB
And now, you can see only x-value of Q, which is 7d9e93308e6105308d46b3a7912844fbd0925f920381501c19fc21716b6b4adb. This alone is enough, to commit to the message, under some public key. Then, someone reveals these things:
Code:
+------------------+------------------------------------------------------------------+
| Q (external key) | 7d9e93308e6105308d46b3a7912844fbd0925f920381501c19fc21716b6b4adb |
+------------------+------------------------------------------------------------------+
| P (internal key) | bb0cc84db7b318cb9f3521b809530440de0870f8e53d075298d06b10018162b8 |
| m (message)      | 6d657373616765 //"message"                                       |
+------------------+------------------------------------------------------------------+
Which means, that external key can be seen in your output, and everything else goes to the witness. Then, when things are validated, the same algorithm is used. The message is hashed, added to the internal key through secp256k1 point addition, and it should match the external key exactly, when it comes to the reached x-value of the public key.

And then, people have two options: they can sign things with external key, by just making a signature, which would match it, or they can reveal the internal key, and some data, which will then decide, how things should be processed, and if any keys are needed at all. Because the message could be like "<pubkey> OP_CHECKSIG", but it could be anything else at all, for example "OP_TRUE".
Sterlino
Newbie
*
Offline

Activity: 9
Merit: 1


View Profile
August 23, 2026, 03:19:42 AM
Merited by athanred (1)
 #3

@athanred I understand the Taproot output key after tweaking the internal key.
but I still don't clearly understand how "message" was found at the end of the scrptpath?
athanred
Member
**
Offline

Activity: 100
Merit: 158


View Profile
August 23, 2026, 05:19:53 AM
 #4

Quote
how "message" was found at the end of the scrptpath?
It is simply chosen by the user. If it exists at all, is it valid, and how it looks like, is checked only during spending. When you send coins to that address as an output, then it is not checked at all.

In the same way, you can have P2WSH, set to OP_TRUE. When you send the coins there, you use bc1qft5p2uhsdcdc3l2ua4ap5qqfg4pjaqlp250x7us7a8qqhrxrxfsq2gp3gp address. At that point, the network doesn't check the Script under it. The only known thing, is that the hash of it is set to 4ae81572f06e1b88fd5ced7a1a000945432e83e1551e6f721ee9c00b8cc33260 and only during spending, it is validated at all.

Which is why you could send coins to addresses like 1BitcoinEaterAddressDontSendf59kuE. Here, the network knows, that the public key should hash into 759d6677091e973b9e9d99f19c68fbf43e3f05f9 but is there any key like that, and how it looks like? Nobody knows, because it is checked only during spending.

Which also means, that if someone wants to lock coins on some hard, or mathematically impossible conditions, then the network won't block it.
Danish Ali
Jr. Member
*
Offline

Activity: 42
Merit: 46


View Profile
August 23, 2026, 07:54:15 PM
 #5

@athanred I understand the Taproot output key after tweaking the internal key.
but I still don't clearly understand how "message" was found at the end of the scrptpath?

While the explanation provided by athanred is wonderful in terms of how math of the tweak is done, does not explain how the merkle root (m) is rebuilt if there are multiple scripts in the merkle tree (not a single one).
This is done by the control block. It contains:

1 parity bit + the internal key P.
A list of 32-byte sibling hashes for each level, the merkle path.

To check: node reads the script (leaf) displayed and hashes it to a TapLeaf hash.

Then it walks up the tree combining the leaf hash with each hash along the way located in the control block (sorted/paired in the same order it was got on the tree building), until it reaches single 32-byte value, that is the rebuilt merkle root m.

With m built in this way it is put into the same formula that athanred mentioned: Q = P + H_TapTweak(P || m)G. If it does agree with the actual output x-value (and parity from control block), then the script is checked to be one of the leaves actually committed at output-creation time, and not made up at the time of show.

Single-script outputs (such as athanred's) are just the simple case of an empty merkle path and m being the hash of the leaf only. But, the node features a hash list of the control block (of which there are many scripts) such that it can demonstrate 'this particular script really was one of several committed into the tree', without revealing the other scripts.
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!