Add rawtr() descriptor for P2TR with specified (tweaked) output key #23480

pull sipa wants to merge 3 commits into bitcoin:master from sipa:202110_untweakedtr changing 5 files +59 −3
  1. sipa commented at 4:33 am on November 10, 2021: member

    It may be useful to be able to represent P2TR outputs in descriptors whose script tree and/or internal key aren’t known. This PR does that, by adding a rawtr(KEY) descriptor, where the KEY represents the output key directly. If the private key corresponding to that output key is known, it also permits signing with it.

    I’m not convinced this is desirable, but presumably “tr(KEY)” sounds more intended for direct use than “rawtr(KEY)”.

  2. DrahtBot added the label Descriptors on Nov 10, 2021
  3. in doc/descriptors.md:76 in 252a9b832a outdated
    72@@ -73,6 +73,7 @@ Descriptors consist of several types of expressions. The top level expression is
    73 - `tr(KEY)` or `tr(KEY,TREE)` (top level only): P2TR output with the specified key as internal key, and optionally a tree of script paths.
    74 - `addr(ADDR)` (top level only): the script which ADDR expands to.
    75 - `raw(HEX)` (top level only): the script whose hex encoding is HEX.
    76+- `rawtr(KEY)` (top level only): P2TR output with the specified key as tweaked key.
    


    benthecarman commented at 8:17 am on November 11, 2021:
    I think saying tweaked key could be confusing unless you know what’s going on under the hood of taproot. Maybe something like output key would be better

    sipa commented at 6:51 pm on November 11, 2021:
    Agree.

    Sjors commented at 8:08 pm on November 12, 2021:
    Or maybe call it pre-tweaked. I can see how that’s more useful than a raw descriptor with the tweaked key.

    sipa commented at 2:43 pm on February 14, 2022:
    Done, renamed to “output key”.
  4. sipa commented at 5:39 pm on November 11, 2021: member
    @apoelstra @real-or-random @jonasnick @sanket1729 Perhaps the documentation here needs some disclaimer at least about the potential pitfalls of using it directly to construct a wallet. It’s not intended for that purpose, only for things like representing otherwise incomplete knowledge in e.g. inference, but adding it to the descriptor language does make it available for all purposes. Can you help think about examples/pitfalls that could be listed?
  5. sanket1729 commented at 1:30 pm on November 12, 2021: contributor

    Agreed that the documentation needs a disclaimer. The two drawbacks that I can think of.

    1. This one is listed in the BIP 341: If people directly use output keys in aggregation using proofs of knowledge.(https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_ref-22-0)
    2. In future protocol constructions, it might be desirable to prove that there is no script path given TxOut/ScriptPubKey/Address. This is not possible when using rawtr(), but is possible with tr() by revealing the internal key.

    Some more points for discussion:

    • Can we separate descriptors into two types in the spec itself? So, we can have addr, raw, rawtr into the infer-only category. The rest into another category that we can sign. In the infer only category, we can restrict the KEY expression to be a concrete public key without any BIP32 derivations or wildcards.

    • Correct me if I am wrong if the only use of inferred descriptors is that I can give it another party for watching a particular txout for me without revealing/knowing how the txout was constructed. So, assuming we disallow signing rawtr() (to encourage the usage of tr ) is there is any use of rawtr() over raw()?

  6. real-or-random commented at 2:19 pm on November 12, 2021: contributor
    The only pitfall I see is the one mentioned by @sanket1729 : rawtr() is potentially incomplete information because there could always be another way to spend that you don’t know about… But that’s exactly its feature, so I guess it’s fine. Anyway, I think if you do “raw” stuff, you should be know what you’re doing.
  7. Sjors commented at 3:40 pm on November 12, 2021: member
    • is there is any use of rawtr() over raw()?

    I second that question.

  8. sipa commented at 3:46 pm on November 12, 2021: member

    Right; I guess the only advantage of rawtr over raw/addr is dealing with cases where the public key is either actually untweaked (and e.g. you need want to provide origin information along with it) or it is tweaked in an unknown way, but you have the tweaked private key.

    raw() in those cases cannot represent all information you have, while rawtr can.

  9. apoelstra commented at 3:55 pm on November 12, 2021: contributor

    Agree with Sanket’s comments. I also agree that having raw in the name should be sufficient warning for users to avoid this, especially since it’s not any harder to use tr.

    Regarding the usefulness, I think it’s definitely useful for “infer-only” cases like running scanutxoset. May also be useful for recovery scenarios … although it’s hard for me to think of a case where you’ve generated a weird Taproot key but somehow need Bitcoin Core to spend it.

  10. sipa commented at 9:35 pm on November 23, 2021: member
    @apoelstra https://twitter.com/achow101/status/1459617340123926534 may or may not have been related. Arguably, not a good justification, but a use case nonetheless…
  11. apoelstra commented at 2:43 pm on December 5, 2021: contributor
    Not the worst usecase :) I use vanity addresses in Liquid test networks sometimes to make logs easier to read and having descriptor support in Core could plausibly make that better.
  12. sanket1729 commented at 0:02 am on January 1, 2022: contributor

    A usecase for rawtr. Note that this protocol is not reviewed(and might be insecure), but I am starting to think we don’t want to preclude people from using new ways to create output keys. In this protocol, it is still possible to prove that there is no script spend using a different way than revealing the internal key. Such proof is not required for the correctness above protocol, but it highlights that there might be other ways to prove the non-existence of script spend than revealing the internal key.

    Although as I mentioned later in response comment, this can also be made compatible with tr descriptor. But doing so would be inefficient and it offers no benefit because we can already prove that there is no script spend.

    Overall, I am leaning towards a concept ACK for this.

  13. DrahtBot commented at 7:52 am on January 26, 2022: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #24897 ([Draft / POC] Silent Payments by w0xlt)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  14. sipa force-pushed on Feb 14, 2022
  15. w0xlt commented at 0:50 am on March 24, 2022: contributor

    Should tr(xpriv) and rawtr(xpriv) return different addresses ?

    I created two blank wallets and imported tr(xpriv) into one and rawtr(xpriv) into the other. The xpriv was the same.

    The addresses have the same desc property but not the same address, as seen below.

    There are also some fields missing from the address generated from rawtr(xpriv) like timestamp.

     0$ ./src/bitcoin-cli -regtest -named createwallet wallet_name=tr_test blank=true
     1
     2$ ./src/bitcoin-cli -regtest importdescriptors "[{\"desc\": \"tr(tprv8ZgxMBicQKsPdKziibn63Rm6aNzp7dSjDnufZMStXr71Huz7iihCRpbZZZ6Voy5HyuHCWx6foHMipzMzUq4tZrtkZ24DJwz5EeNWdsuwX5h/*)#223d6gp6\", \"active\": true, \"timestamp\": \"now\"}]"
     3
     4$ ./src/bitcoin-cli -regtest -named createwallet wallet_name=rawtr_test blank=true
     5
     6$ ./src/bitcoin-cli -regtest -rpcwallet="rawtr_test" importdescriptors "[{\"desc\": \"rawtr(tprv8ZgxMBicQKsPdKziibn63Rm6aNzp7dSjDnufZMStXr71Huz7iihCRpbZZZ6Voy5HyuHCWx6foHMipzMzUq4tZrtkZ24DJwz5EeNWdsuwX5h/*)#223d6gp6\", \"active\": true, \"timestamp\": \"now\"}]"
     7
     8$ ./src/bitcoin-cli -regtest -rpcwallet="tr_test" -named getnewaddress address_type='bech32m'
     9bcrt1p8eafa4hnyfae7kyc42ehndduu49zfuhneerma58j2xexc6lx5wxsm8e5j7
    10
    11$ ./src/bitcoin-cli -regtest -rpcwallet="rawtr_test" -named getnewaddress address_type='bech32m'
    12bcrt1pqwnxn65jduuptqhvfgqqh9rjh29pwdrlt7c4nmwafgrsx6n8rr4supy9dh
    13
    14$ ./src/bitcoin-cli -regtest -rpcwallet="rawtr_test" getaddressinfo "bcrt1pqwnxn65jduuptqhvfgqqh9rjh29pwdrlt7c4nmwafgrsx6n8rr4supy9dh"
    15{
    16  "address": "bcrt1pqwnxn65jduuptqhvfgqqh9rjh29pwdrlt7c4nmwafgrsx6n8rr4supy9dh",
    17  "scriptPubKey": "512003a669ea926f381582ec4a000b9472ba8a17347f5fb159eddd4a07036a6718eb",
    18  "ismine": true,
    19  "solvable": true,
    20  "desc": "rawtr([8324d0e9/0]03a669ea926f381582ec4a000b9472ba8a17347f5fb159eddd4a07036a6718eb)#5rk6yanl",
    21  "parent_desc": "rawtr(tpubD6NzVbkrYhZ4Wo2WcFSgSqRD9QWkGxddo6WSqsVBx7uQ8QEtM7WncKDRjhFEexK119NigyCsFygA4b7sAPQxqebyFGAZ9XVV1BtcgNzbCRR/*)#x2xz0lq0",
    22  "iswatchonly": false,
    23  "isscript": true,
    24  "iswitness": true,
    25  "witness_version": 1,
    26  "witness_program": "03a669ea926f381582ec4a000b9472ba8a17347f5fb159eddd4a07036a6718eb",
    27  "ischange": false,
    28  "labels": [
    29    ""
    30  ]
    31}
    32
    33$ ./src/bitcoin-cli -regtest -rpcwallet="tr_test" getaddressinfo "bcrt1p8eafa4hnyfae7kyc42ehndduu49zfuhneerma58j2xexc6lx5wxsm8e5j7"
    34{
    35  "address": "bcrt1p8eafa4hnyfae7kyc42ehndduu49zfuhneerma58j2xexc6lx5wxsm8e5j7",
    36  "scriptPubKey": "51203e7a9ed6f3227b9f5898aab379b5bce54a24f2f3ce47bed0f251b26c6be6a38d",
    37  "ismine": true,
    38  "solvable": true,
    39  "desc": "tr([8324d0e9/0]03a669ea926f381582ec4a000b9472ba8a17347f5fb159eddd4a07036a6718eb)#05zmkxzl",
    40  "parent_desc": "tr(tpubD6NzVbkrYhZ4Wo2WcFSgSqRD9QWkGxddo6WSqsVBx7uQ8QEtM7WncKDRjhFEexK119NigyCsFygA4b7sAPQxqebyFGAZ9XVV1BtcgNzbCRR/*)#fdlr9alf",
    41  "iswatchonly": false,
    42  "isscript": true,
    43  "iswitness": true,
    44  "witness_version": 1,
    45  "witness_program": "3e7a9ed6f3227b9f5898aab379b5bce54a24f2f3ce47bed0f251b26c6be6a38d",
    46  "ischange": false,
    47  "timestamp": 1646090838,
    48  "hdkeypath": "m/0",
    49  "hdseedid": "0000000000000000000000000000000000000000",
    50  "hdmasterfingerprint": "8324d0e9",
    51  "labels": [
    52    ""
    53  ]
    54}
    
  16. sipa commented at 1:00 am on March 24, 2022: member

    @w0xlt Yes, that’d definitely expected. rawtr(KEY) literally puts the key in the scriptPubKey directly. tr(KEY) will construct an output key derived from KEY as internal key.

    If the two weren’t different, we wouldn’t need to add rawtr in the first place.

  17. w0xlt commented at 7:47 pm on March 24, 2022: contributor

    @sipa Thanks for the clarification.

    But since the wallet is able to generate multiple addresses for rawtr(KEY), I assumed that there would also be key derivations for KEY in this case.

    For example:

    0# First address
    1"desc":    "tr([8324d0e9/0]03a669ea926f381582ec4a000b9472ba8a17347f5fb159eddd4a07036a6718eb)#05zmkxzl"
    2"desc": "rawtr([8324d0e9/0]03a669ea926f381582ec4a000b9472ba8a17347f5fb159eddd4a07036a6718eb)#5rk6yanl"
    3
    4# Second address
    5"desc":    "tr([8324d0e9/1]bbf56b14b119bccafb686adec2e3d2a6b51b1626213590c3afa815d1fd36f85d)#0djkz4yx"
    6"desc": "rawtr([8324d0e9/1]bbf56b14b119bccafb686adec2e3d2a6b51b1626213590c3afa815d1fd36f85d)#56xhsw4x"
    

    Shouldn’t rawtr() generate just a single address ?

  18. sipa commented at 7:59 pm on March 24, 2022: member
    Different keys give rise to different addresses….
  19. sipa force-pushed on Apr 5, 2022
  20. sipa commented at 7:31 pm on April 5, 2022: member
    Rebased.
  21. w0xlt commented at 4:19 pm on April 12, 2022: contributor

    It looks like the CI is failing due to the difference between the expected result and the RPC result in rpc_decodescript.py:decodescript_datadriven_tests().

    Script (first element in rpc_decodescript.json): 5120eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee

    Expected result: {'asm': '1 eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', 'address': 'bcrt1pamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhqz6nvlh', 'desc': 'addr(bcrt1pamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhqz6nvlh)#v52jnujz', 'type': 'witness_v1_taproot'}

    RPC result: {'asm': '1 eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', 'desc': 'rawtr(eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee)#jk7c6kys', 'address': 'bcrt1pamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhqz6nvlh', 'type': 'witness_v1_taproot'}

  22. w0xlt commented at 6:10 pm on April 12, 2022: contributor
    wallet_taroot.py is also failing. Apparently the PSBT is not completing and assert(res['complete']) fails.
  23. sipa commented at 7:11 pm on April 12, 2022: member
    I’ll get back to this soon.
  24. w0xlt referenced this in commit cb9d6b2f17 on Apr 13, 2022
  25. w0xlt referenced this in commit 763bcad920 on Apr 13, 2022
  26. w0xlt referenced this in commit 4400d4d7fc on Apr 13, 2022
  27. w0xlt referenced this in commit 6534fe7ef9 on Apr 16, 2022
  28. w0xlt referenced this in commit 829e5996e9 on Apr 17, 2022
  29. w0xlt referenced this in commit 5d2aeaa389 on Apr 19, 2022
  30. w0xlt referenced this in commit 67b5059459 on Apr 27, 2022
  31. w0xlt commented at 12:56 pm on May 5, 2022: contributor

    I noticed the behavior below. I’m not sure if it’s as expected.

    The address bcrt1...8n6wyskueguk returns the tr(...) descriptor in getaddressinfo RPC, which looks correct as it was generated via getnewaddress '' 'bech32m' But when this same address is used as the recipient of a transaction, its descriptor is displayed as rawtr(...), as seen below.

     0$ bitcoin-cli -regtest -rpcwallet="receiver" getnewaddress '' 'bech32m'
     1bcrt1pwlhw9uxkga774g6er3hthkaa4npvr2zcutt4gcqxyf5f2y8n6wyskueguk
     2
     3$ bitcoin-cli -regtest -rpcwallet="receiver" getaddressinfo "bcrt1pwlhw9uxkga774g6er3hthkaa4npvr2zcutt4gcqxyf5f2y8n6wyskueguk"
     4{
     5  "address": "bcrt1pwlhw9uxkga774g6er3hthkaa4npvr2zcutt4gcqxyf5f2y8n6wyskueguk",
     6  "scriptPubKey": "512077eee2f0d6477deaa3591c6ebbdbbdacc2c1a858e2d754600622689510f3d389",
     7  ...
     8  "desc": "tr([92c4c112/86'/1'/0'/0/0]a612d64e3415afb653e98da12bb34a9c0785a10c6880cbf0436791a89428826b)#f67tyh68",
     9  ...
    10}
    11
    12$ bitcoin-cli -regtest -rpcwallet="sender" -named send outputs="{\"bcrt1pwlhw9uxkga774g6er3hthkaa4npvr2zcutt4gcqxyf5f2y8n6wyskueguk\": 12.00000381}" fee_rate=1 options="{\"add_to_wallet\": false }"
    13{
    14  ...
    15  "hex": "020000...ca3078fbd0900000000"
    16}
    17
    18$ bitcoin-cli -regtest decodetransaction "020000...ca3078fbd0900000000"
    19{
    20  "txid": "fa4f78fc970bbae4e932690b5b9370d18545316f43fa126991a0e76cf57a1e63",
    21  "hash": "dc5ac5d41fd0cf0b4990f9cafb3b64eac5b05680776e80c61f3867ee51b70df2",
    22  "version": 2,
    23  ...
    24  "vout": [
    25    {
    26      "value": 12.00000381,
    27      "n": 0,
    28      "scriptPubKey": {
    29        "asm": "1 77eee2f0d6477deaa3591c6ebbdbbdacc2c1a858e2d754600622689510f3d389",
    30        "desc": "rawtr(77eee2f0d6477deaa3591c6ebbdbbdacc2c1a858e2d754600622689510f3d389)#u26fgmea",
    31        "hex": "512077eee2f0d6477deaa3591c6ebbdbbdacc2c1a858e2d754600622689510f3d389",
    32        "address": "bcrt1pwlhw9uxkga774g6er3hthkaa4npvr2zcutt4gcqxyf5f2y8n6wyskueguk",
    33        "type": "witness_v1_taproot"
    34      }
    35    },
    36    ...
    37  ]
    38}
    
  32. sipa commented at 2:47 pm on May 5, 2022: member
    @w0xlt Yes, that’s expected. The sender doesn’t know the internal public key the receiver is using (in tr(KEY) the KEY is the internal key), so it can only show the tweaked key (in rawtr(KEY) the KEY is the tweaked key).
  33. w0xlt referenced this in commit 42ba0268d0 on May 5, 2022
  34. w0xlt referenced this in commit 94f7187fbc on May 22, 2022
  35. theStack commented at 12:48 pm on May 27, 2022: contributor
    Concept ACK
  36. sipa force-pushed on May 27, 2022
  37. sipa commented at 4:16 pm on May 27, 2022: member
    Rebased.
  38. w0xlt referenced this in commit 2a1cbc6191 on Jun 4, 2022
  39. sipa commented at 6:21 pm on June 8, 2022: member
    Rebased.
  40. sipa force-pushed on Jun 8, 2022
  41. real-or-random commented at 11:07 am on June 9, 2022: contributor
  42. michaelfolkson commented at 2:45 pm on June 14, 2022: contributor

    Concept ACK. Agree with @sanket1729’s thoughts.

    A usecase for rawtr. Note that this protocol is not reviewed(and might be insecure), but I am starting to think we don’t want to preclude people from using new ways to create output keys.

    As others have said wallet_taproot.py is still failing. I’m getting a:

    TypeError: do_test() takes 5 positional arguments but 6 were given on Line 449.

    0self.do_test(
    1            "rawtr(XPRV)",
    2            "rawtr($1/*)",
    3            [True],
    4            lambda k1: key(k1),
    5            1
    6        )
    

    Is the 1 needed?

    edit: Removing the 1 hits the assert(res['complete']) previously encountered error again.

  43. sipa force-pushed on Jun 17, 2022
  44. sipa force-pushed on Jun 17, 2022
  45. sipa commented at 9:14 pm on June 17, 2022: member
    Rebased, and hopefully fixed test failures.
  46. in src/script/descriptor.cpp:933 in 16c1929fd5 outdated
    928+        if (!xpk.IsFullyValid()) return {};
    929+        WitnessV1Taproot output{xpk};
    930+        return Vector(GetScriptForDestination(output));
    931+    }
    932+public:
    933+    RawTRDescriptor(std::unique_ptr<PubkeyProvider> internal_key) : DescriptorImpl(Vector(std::move(internal_key)), "rawtr") {}
    


    sanket1729 commented at 9:38 pm on June 17, 2022:

    nit: here and elsewhere

    Perhaps better renamed as output_key over internal_key


    sipa commented at 10:17 pm on July 19, 2022:
    Done.
  47. sanket1729 approved
  48. sanket1729 commented at 9:39 pm on June 17, 2022: contributor
    ACK left one small nit. Feel free to ignore
  49. w0xlt approved
  50. w0xlt commented at 3:25 am on June 18, 2022: contributor

    Tested ACK https://github.com/bitcoin/bitcoin/pull/23480/commits/9342970d7253abbf97c2bde6c242e29d9445c311.

    This rawtr implementation is used in PR #24897 and has been successfully stored and spent on signet.

  51. real-or-random commented at 10:10 pm on June 18, 2022: contributor

    Perhaps the documentation here needs some disclaimer at least about the potential pitfalls of using it directly to construct a wallet.

    I think the doc part is still unresolved?

  52. DrahtBot added the label Needs rebase on Jul 14, 2022
  53. w0xlt commented at 11:09 pm on July 15, 2022: contributor

    This might fix the CI errors: In test/functional/wallet_taproot.py (https://github.com/bitcoin/bitcoin/pull/23480/commits/9342970d7253abbf97c2bde6c242e29d9445c311):

    0  from test_framework.key import H_POINT
    1+ from test_framework.segwit_addr import encode_segwit_address
    
  54. w0xlt referenced this in commit b2a1a501e0 on Jul 15, 2022
  55. Add rawtr() descriptor for P2TR with unknown tweak 8d9670ccb7
  56. If P2TR tweaked key is available, sign with it e1e3081200
  57. Add wallet tests for spending rawtr() 544b4332f0
  58. sipa force-pushed on Jul 19, 2022
  59. sipa commented at 10:22 pm on July 19, 2022: member

    Rebased, and made a few changes:

  60. sanket1729 approved
  61. sanket1729 commented at 10:30 pm on July 19, 2022: contributor
    code review ACK 544b4332f0e122167bdb94dc963405422faa30cb
  62. DrahtBot removed the label Needs rebase on Jul 19, 2022
  63. w0xlt approved
  64. w0xlt referenced this in commit 2028c1c8b4 on Aug 1, 2022
  65. w0xlt referenced this in commit 94889d3b3e on Aug 3, 2022
  66. w0xlt referenced this in commit 736626fcd6 on Aug 9, 2022
  67. achow101 commented at 8:26 pm on August 9, 2022: member
    ACK 544b4332f0e122167bdb94dc963405422faa30cb
  68. achow101 merged this on Aug 9, 2022
  69. achow101 closed this on Aug 9, 2022

  70. w0xlt referenced this in commit d377e74768 on Aug 10, 2022
  71. sidhujag referenced this in commit f0b6570b37 on Aug 10, 2022
  72. w0xlt referenced this in commit 6ceac993cd on Aug 17, 2022
  73. w0xlt referenced this in commit 097f55fd97 on Aug 20, 2022
  74. w0xlt referenced this in commit 9088ecaea7 on Sep 4, 2022
  75. w0xlt referenced this in commit d69c0d70fc on Sep 15, 2022
  76. w0xlt referenced this in commit 8edd7c2f23 on Sep 29, 2022
  77. w0xlt referenced this in commit 6f70adb556 on Oct 5, 2022
  78. w0xlt referenced this in commit 1f0efc8ef0 on Oct 5, 2022
  79. w0xlt referenced this in commit 1f0ad16df6 on Oct 10, 2022
  80. w0xlt referenced this in commit f790f10b7a on Oct 13, 2022
  81. bitcoin locked this on Aug 9, 2023

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-12-21 15:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me