I want to create a P2TR (Pay to Taproot) address but I just want access to the key path spend, I have no use for the script path spend in this specific example. What should I do in regard to the script path in that case?
2 Answers
BIP 341 (BIP-Taproot) discusses this example where you don't require the script path.
If the spending conditions do not require a script path, the output key should commit to an unspendable script path instead of having no script path.
The BIP also explains here the rationale for this.
If the taproot output key is an aggregate of keys, there is the possibility for a malicious party to add a script path without being noticed by the other parties. This allows to bypass the multiparty policy and to steal the coins.
Committing to an unspendable script path provides the ability to prove to a third party observer that there is no hidden script path. If there was no tweak at all any key aggregation scheme would need to be revealed to that observer including individual pubkeys to get the same effect (and even this may not be enough for certain key aggregation schemes).
The Bitcoin Optech workshop on Taproot explains that you calculate the tweaked public key using:
Q = P + H(P|c)G
where
Q is the tweaked public key
P is the initial public key (P = xG where x is the private key)
H is the hash function
| is concatenation
c is the commitment to the script path spend
G is the generator point
If you don't need the script path spend you can calculate the tweaked public key using:
Q = P + H(bytes(P))G
where bytes(P)
is the serialization of P as defined in BIP 340 (BIP-Schnorr).
This tweaked public key Q will be your Taproot (P2TR) address. Remember we don't hash (tweaked) public keys with Taproot (SegWit v1) like we do with P2PKH, P2SH, P2WSH (SegWit v0).
-
How does it work that 'Committing to an unspendable script path provides the ability to prove to a third party observer that there is no hidden script path"? Couldn't there still be, in the resulting script tree, a hidden script path? I just don't get what this means.– davidbakCommented Jun 7, 2022 at 20:06
-
@davidbak: You are effectively revealing that there is a single script path that is hashed and this is what is tweaking your internal public key. For there to be additional script paths you are relying on the equivalent of hash collisions. Not only is the tweak the hash of single script path but the same tweak is also the hash of another (potentially multiple encoded in a Merkle tree) script path. So theoretically possible but practically extremely unlikely. Commented Jun 7, 2022 at 21:59
You can read the following code, the key point is that the root of TapRoot should be an empty array so only the public key is hashed.
def address_p2tr(pubkey: PubKey) -> str:
# Taproot.
# See https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki
if pubkey.y & 1 != 0:
# Taproot requires that the y coordinate of the public key is even.
pubkey = PubKey(pubkey.x, btc.secp256k1.P - pubkey.y)
adjust_prikey = btc.secp256k1.Fr(int.from_bytes(hashtag('TapTweak', bytearray(pubkey.x.to_bytes(32)))))
adjust_pubkey = btc.secp256k1.G * adjust_prikey
output_pubkey = btc.secp256k1.Pt(btc.secp256k1.Fq(pubkey.x), btc.secp256k1.Fq(pubkey.y)) + adjust_pubkey
return btc.bech32.encode(btc.config.current.prefix.bech32, 1, bytearray(output_pubkey.x.x.to_bytes(32)))