BIP394: rawtr() Output Script Descriptors

This commit is contained in:
jeanpablojp committed 2026-11-06 13:10:19 +00:00
1 parent c38071c8c4
commit bc8b68c9cf
3 files changed
+130

No files matched your search

+7
View File
@@ -1430,6 +1430,13 @@ users (see also: [https://en.bitcoin.it/wiki/Economic_majority economic majority
| Specification | Specification
| Draft | Draft
|- |-
| [[bip-0394.mediawiki|394]]
| Applications
| rawtr() Output Script Descriptors
| jeanpablojp
| Specification
| Draft
|-
| [[bip-0431.mediawiki|431]] | [[bip-0431.mediawiki|431]]
| Applications | Applications
| Topology Restrictions for Pinning | Topology Restrictions for Pinning
+3
View File
@@ -341,4 +341,7 @@ This Table lists all available Script expressions and the BIPs specifying them.
|- |-
| <tt>sp(KEY)</tt>, <tt>sp(KEY, KEY)</tt> | <tt>sp(KEY)</tt>, <tt>sp(KEY, KEY)</tt>
| [[bip-0392.mediawiki|392]] | [[bip-0392.mediawiki|392]]
|-
| <tt>rawtr(KEY)</tt>
| [[bip-0394.mediawiki|394]]
|} |}
+120
View File
@@ -0,0 +1,120 @@
<pre>
BIP: 394
Layer: Applications
Title: rawtr() Output Script Descriptors
Authors: jeanpablojp <me@jeanpablo.jp>
Status: Draft
Type: Specification
Assigned: 2026-09-09
License: BSD-2-Clause
Discussion: 2026-03-02: https://github.com/bitcoin/bips/pull/2050#issuecomment-3986205616
2026-08-06: https://groups.google.com/g/bitcoindev/c/CCZN_qQ5C1s
Requires: 341, 380
</pre>
==Abstract==
This document specifies <tt>rawtr()</tt> output script descriptors.
A <tt>rawtr()</tt> descriptor expresses a Pay-to-Taproot output by its output key directly, without stating an internal key or a script tree.
==Motivation==
A taproot output key is derived from an internal key and an optional script tree, as described in [[bip-0341.mediawiki|BIP 341]].
The <tt>tr()</tt> descriptor specified in [[bip-0386.mediawiki|BIP 386]] takes the internal key and the tree, and computes the output key from them.
There is no way to use <tt>tr()</tt> for an output whose internal structure isn't known, for example an output key received from another party, or one whose script tree the holder does not wish to reveal.
The <tt>rawtr()</tt> descriptor covers that case by taking the output key itself.
This expression has been implemented in Bitcoin Core since version 24.0, and [[bip-0390.mediawiki|BIP 390]] permits <tt>musig()</tt> inside <tt>rawtr()</tt> and uses it in its test vectors.
This document gives the expression a specification of its own.
==Specification==
A new script expression is defined: <tt>rawtr()</tt>.
The <tt>rawtr(KEY)</tt> expression can only be used as a top level descriptor.
It takes a single key expression as an argument and produces a P2TR output script.
Unlike <tt>tr()</tt>, it does not take a tree expression, and the key is used directly as the taproot output key, with no [[bip-0341.mediawiki|BIP 341]] tweak applied.
The output script produced is:
<pre>
OP_1 <KEY>
</pre>
Key expressions within a <tt>rawtr()</tt> expression must only create x-only public keys, as in <tt>tr()</tt> expressions.
Uncompressed public keys are not allowed. Compressed public keys are allowed, but will be implicitly converted to x-only public keys.
The keys derived from extended keys must be serialized as x-only public keys.
If the private key corresponding to the output key is known, the output can be spent via the key path.
Note that a <tt>rawtr()</tt> descriptor cannot show whether a script path exists for the output: nothing in it proves that the output key does not commit to a script tree.
Software importing a <tt>rawtr()</tt> descriptor from an untrusted source should warn that other spending paths may exist.
==Rationale==
No [[bip-0341.mediawiki|BIP 341]] tweak is applied to the key, since tweaking it would describe a different output than the one the descriptor is for.
The expression is top level only, because a P2TR output script is a complete scriptPubKey and there is no context in which it can appear as a sub-expression.
Key expressions are restricted to x-only public keys because a taproot output key is an x-only key.
Compressed public keys are accepted and converted implicitly, as in <tt>tr()</tt>, so a key expression written for one of the two also works in the other.
The absence of a specification has already produced divergence outside Bitcoin Core.
rust-miniscript renders these outputs as <tt>rawtr_not_supported_yet(KEY)</tt> and does not parse them back, and the bdk-ffi descriptor tests describe <tt>rawtr()</tt> as [[bip-0386.mediawiki|BIP 386]], which specifies <tt>tr()</tt>.
==Test Vectors==
Valid descriptors followed by the scripts they produce. Descriptors involving derived child keys will have the 0th, 1st, and 2nd scripts listed. These vectors were generated with Bitcoin Core's descriptor implementation. Note that the first vector uses the same key as the first <tt>tr()</tt> vector of [[bip-0386.mediawiki|BIP 386]]: with <tt>rawtr()</tt> the key appears in the script unchanged, while <tt>tr()</tt> tweaks it. The third vector takes the output key that the BIP 386 vector produced and reproduces its script.
* <tt>rawtr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)</tt>
** <tt>5120a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd</tt>
* <tt>rawtr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)</tt>
** <tt>5120a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd</tt>
* <tt>rawtr(77aab6e066f8a7419c5ab714c12c67d25007ed55a43cadcacb4d7a970a093f11)</tt>
** <tt>512077aab6e066f8a7419c5ab714c12c67d25007ed55a43cadcacb4d7a970a093f11</tt>
* <tt>rawtr(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)</tt>
** <tt>5120a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd</tt>
* <tt>rawtr(02a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)</tt>
** <tt>5120a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd</tt>
* <tt>rawtr(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/0/*)</tt>
** <tt>51208145454b87fc9ec3557478d6eadc2aea290b50f3c469b828abeb542ae8f8849d</tt>
** <tt>5120377ad06450813b5f7e10bc94b8b662513398c2d83086f8e67349a00909a5a5a4</tt>
** <tt>51200a862a965e930b917327d4d08e6309aeb6a4fb0970e133c8ea0d034de04cc3b0</tt>
* <tt>rawtr(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/<0;1>/*)</tt>, a multipath descriptor as specified in [[bip-0389.mediawiki|BIP 389]], expanding into two descriptors:
** <tt>rawtr(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*)</tt>
*** <tt>51208145454b87fc9ec3557478d6eadc2aea290b50f3c469b828abeb542ae8f8849d</tt>
*** <tt>5120377ad06450813b5f7e10bc94b8b662513398c2d83086f8e67349a00909a5a5a4</tt>
*** <tt>51200a862a965e930b917327d4d08e6309aeb6a4fb0970e133c8ea0d034de04cc3b0</tt>
** <tt>rawtr(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*)</tt>
*** <tt>5120095e95d8c50ae3f3fea93fa8e983f710489f60ff681a658c06eba64622c824b1</tt>
*** <tt>51207512d6bd74e24eeb1ad752d5be800adc5886ded11c5293a9a701db83658b526a</tt>
*** <tt>5120cc9fd211dc0a1c8bb7a106ff831be0e253bc992f21d08fb8a6fd43fae51b9b89</tt>
* <tt>rawtr(musig(KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU74sHUHy8S,03dff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659,023590a94e768f8e1815c2f24b4d80a8e3149316c3518ce7b7ad338368d038ca66))</tt>, from the [[bip-0390.mediawiki|BIP 390]] test vectors
** <tt>5120789d937bade6673538f3e28d8368dda4d0512f94da44cf477a505716d26a1575</tt>
* <tt>rawtr(musig(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y)/0/*)</tt>, from the [[bip-0390.mediawiki|BIP 390]] test vectors
** <tt>51209508c08832f3bb9d5e8baf8cb5cfa3669902e2f2da19acea63ff47b93faa9bfc</tt>
** <tt>51205ca1102663025a83dd9b5dbc214762c5a6309af00d48167d2d6483808525a298</tt>
** <tt>51207dbed1b89c338df6a1ae137f133a19cae6e03d481196ee6f1a5c7d1aeb56b166</tt>
Invalid Descriptors
* <tt>rawtr()</tt> nested in <tt>sh</tt>: <tt>sh(rawtr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))</tt>
* <tt>rawtr()</tt> nested in <tt>wsh</tt>: <tt>wsh(rawtr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))</tt>
* Script expression instead of a key expression: <tt>rawtr(pk(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))</tt>
* More than one key: <tt>rawtr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,77aab6e066f8a7419c5ab714c12c67d25007ed55a43cadcacb4d7a970a093f11)</tt>
* Tree expression, which <tt>rawtr()</tt> does not take: <tt>rawtr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,pk(77aab6e066f8a7419c5ab714c12c67d25007ed55a43cadcacb4d7a970a093f11))</tt>
* Uncompressed private key: <tt>rawtr(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)</tt>
* Uncompressed public key: <tt>rawtr(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)</tt>
* No key: <tt>rawtr()</tt>
* X-only key with no point on the curve: <tt>rawtr(0000000000000000000000000000000000000000000000000000000000000005)</tt>
==Backwards Compatibility==
<tt>rawtr()</tt> descriptors use the format and general operation specified in [[bip-0380.mediawiki|380]].
This is a wholly new descriptor, and as such is not compatible with any implementation that predates it.
The scripts produced are standard Pay-to-Taproot scripts, so existing software is likely to be familiar with them.
==Reference Implementation==
<tt>rawtr()</tt> descriptors have been implemented in Bitcoin Core since version 24.0.
==Copyright==
This BIP is licensed under the BSD 2-clause license.