From mboxrd@z Thu Jan 1 00:00:00 1970 Delivery-date: Fri, 20 Feb 2026 13:07:18 -0800 Received: from mail-oi1-f184.google.com ([209.85.167.184]) by mail.fairlystable.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1vtXiX-0001FL-Gk for bitcoindev@gnusha.org; Fri, 20 Feb 2026 13:07:18 -0800 Received: by mail-oi1-f184.google.com with SMTP id 5614622812f47-463905cb295sf10634635b6e.2 for ; Fri, 20 Feb 2026 13:07:16 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1771621631; cv=pass; d=google.com; s=arc-20240605; b=aXsRqHso08XwgMqk9RXdFcc5uGjTDFKKRnFf5SeoAwpUj7yiPqVi/hBOd+6320XJaZ m5Ypn4aIIsQtL7S5TlAcKZSole2vC1Pf+gh8gqugXer0e47jC1DvvFoz+NrWkz2Hq/Ek B2ueJhImdmMqbkgpt/PnI1u6PbsoX2lbCUwqMGXiAW32Z2/FuZ4hC1FoiIllsmzANaCB Lh7gPh/2Hd/9dZ7SlgjBuEWBBc3y7DuAoaVCM++rhoDahN+byvJg9SoOg3fzlQJq6qkr 8rFKDHkDR3ZBxFj65f6wvlxG5jx1JkcSItlpFbF+86oJOxU6ZWUVK8VZ54i+rFH5seJt gevA== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:reply-to:mime-version:feedback-id :message-id:subject:from:to:date:dkim-signature; bh=VbvkEqIgvD+QP80NBFXZ1WwWqAVJ4zDX+U4qfsyUykc=; fh=9Td38srSJ282FyYkS7YCVPj07NO0YgqXPocCH4sTdyU=; b=GIUFTsVQACRJUo7U06Vl2oazEoidW9Ood2sK1ndVHg0DjIIAwxJVo6q031HABh2zyp Znsq5XxzNCgSjIwVJDZvJbCmaTKh6WahLWsnJHd8dh1ilIY06kk8pyMH2bJzWAtkDkKr XB2VPfPOG2NQKX6N/Rc1JJkBT3fsMTs1iXwhFMBFVksu8Vd0uUAWTyOk1gzvFXluSCIK 5WpIJ16nyQ3XiZ9feFfCfbwXyv9PaysSIPn+bGI1z5u9TaEFhMrn2kwxuZFiVxo6snI3 ipOK1UHy22GYpBeyPwtXX+XKpaOWCJ7wFw9OKwI59hqGGKS+KGojIUtoro/PPyhDC7p7 AuLw==; darn=gnusha.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@protonmail.com header.s=protonmail3 header.b=US+tq2BE; spf=pass (google.com: domain of darosior@protonmail.com designates 109.224.244.16 as permitted sender) smtp.mailfrom=darosior@protonmail.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=protonmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1771621631; x=1772226431; darn=gnusha.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:reply-to :x-original-authentication-results:x-original-sender:mime-version :feedback-id:message-id:subject:from:to:date:from:to:cc:subject:date :message-id:reply-to; bh=VbvkEqIgvD+QP80NBFXZ1WwWqAVJ4zDX+U4qfsyUykc=; b=BKa2RRsOKyFy3l/ey5HZgK0vZztuCpcJFKzRjJxUZxWfuNBss3eVJMiYHM05UCMCgR Rz3bb/c0bw9c/kIP+Xh9HgRB4XqeBjSPpJH894XwJznF69HOjW5eEBS6n4EFBJ7DDQyC KPnO7PnMda16CTT3fzII1maMrZW+yD593KWy5sYmdni6r6+ixIuK3xhbcPcTE0Xa1UDW MHdge3JP5VRHYPEaUVy1rLHmVML6H02YUBuRoKcPxr3V7MYgki9WopELHsN2xGT4dcVd un+ONHxtvygg6zgZfxlvoaWjR5dvwoEBNFv4ljunSiLvqnGm3qcF7nKyJju4Gl25AUpq S36g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771621631; x=1772226431; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:reply-to :x-original-authentication-results:x-original-sender:mime-version :feedback-id:message-id:subject:from:to:date:x-beenthere :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=VbvkEqIgvD+QP80NBFXZ1WwWqAVJ4zDX+U4qfsyUykc=; b=B0v9mKJOloXRRd+/hap5u2MSVG5wX8DVF4nbjIPvw60C4RGqT3i7HOY996VJibURy6 TIKy+KTgutkNE+S/Ob9GOpEa5yiSBROTyjUaI+lCJ9LMOJPmiTVOONNmJ4uZn1d4X3YS 09P/ZxX90GXXs45uDN+jssv9DX/vTdpRqwcvgkHwFsN3NCdrPMENQ3/mntV2GF2TJZaV UilZ+r42P1Pp52Krxzp7UHBLkAWAiuFq9N1ccRq0piM3F3S78RG6Zg2So7YuKnM/CpaV rAZWuoQsXKq2e40j4JGYWAmGMEB21oCyOQ58x8IpG1MKEp2sQ2tUJr4wMmpUHa3O2JoC 2d7A== X-Forwarded-Encrypted: i=2; AJvYcCVmxFXf9oeuvVxHMFFJBBxUvbwToRiJ5qaTapRW1ThqrvAl2vClfUxsaeelGuSMo9f06PROugIaUY2b@gnusha.org X-Gm-Message-State: AOJu0Yw7MYjxK/3wE3C8THgVUyV8gQ19IseVHynhvjpDl845sgit7GOX mVcBgb8J6SJ5hRT6PtBlPU/d5tNL6PDUZPrzDRjwtBkCvlKNAmXLCZu3 X-Received: by 2002:a05:6808:1524:b0:45f:2719:32a0 with SMTP id 5614622812f47-4644638c788mr773767b6e.42.1771621630849; Fri, 20 Feb 2026 13:07:10 -0800 (PST) X-BeenThere: bitcoindev@googlegroups.com; h="AV1CL+FqJcIyyqTa2yLbhUjG/TarWYr6zFIe0pPSFIizvDijBw==" Received: by 2002:a05:6871:3301:b0:409:6328:a767 with SMTP id 586e51a60fabf-40eca620de7ls6019285fac.1.-pod-prod-04-us; Fri, 20 Feb 2026 13:07:06 -0800 (PST) X-Received: by 2002:a05:6808:4fe6:b0:45e:e8ee:192 with SMTP id 5614622812f47-464463d4960mr821294b6e.56.1771621626371; Fri, 20 Feb 2026 13:07:06 -0800 (PST) Received: by 2002:a05:620a:9146:b0:8cb:7903:6696 with SMTP id af79cd13be357-8cb790373d7ms85a; Fri, 20 Feb 2026 12:38:25 -0800 (PST) X-Received: by 2002:a05:622a:2d2:b0:4ff:b211:6aa6 with SMTP id d75a77b69052e-5070bbd986bmr17862771cf.27.1771619904582; Fri, 20 Feb 2026 12:38:24 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1771619904; cv=none; d=google.com; s=arc-20240605; b=H1WjQPzjuXlO/tuyhlmnddKCpEd4G9Aas6c+koBiGL0puZpppHjKOgnEt/QNTgbgEj 2xhvBqpn0BIiJlm6ngzvvexNk/KEn2ygpfD4tiCgCExHc5+YPcZgHeBaROOhulCvWqgK IK1FAEHuKA0On2GBkhoiMvxR4GiiPmG2lxzcusF6V91JFMXxrqN4xMEQalhO1hmIvu1c PtuM2xS1LSxLwFNs7Xi7PBizg/uMvUS0naV8VfnqwZy27EvqYqUqkfT3ghIMdrKUvBvb Zw8nUpzqUeE0nAxqILJfdVkITGC9uLDwX5oglP41O1rc5mtm/6gmKCyKsBxrxyNdLh8V 1h2Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=content-transfer-encoding:mime-version:feedback-id:message-id :subject:from:to:date:dkim-signature; bh=SV1spCgvpBw/iYMc5EhFpE7FQ9lccUhJFH5+r3mrTM4=; fh=DMP0F9ULS1guKiqimntQRCN8ZraraesEgQuVcn7F0Z0=; b=bevvlnNzlUgjvWTlFik5jY/Tza/xYp9RIwtaUCKIi/znXgOfxIYxc7jrJZNSB9Vg2I 1Cd6NCrmKdW1CUzJ7gLf21e0VqZHrpdz0PDYeclNKbvEVLVSEPYLs6lGLd93ZH9Yq5yQ nk4nZYVQkFRVFcJDGZsJMpzK/S8zwm6PJO5R9GXfFGxvzTzp7bwBpS2WNMkc5s2C535S /yUuhOJ8JzEvxlkpASFLyHj0dSCU4PFhgZe51bxWAhrbCSV+6D+6074mtzbYrY+ihstq SNjZIdn38Nb2bEmuMvEQFrQPA8JvdlvA4hwqMZiy3Adk35xdohdxcGD41SihHVrivqCa rW0Q==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@protonmail.com header.s=protonmail3 header.b=US+tq2BE; spf=pass (google.com: domain of darosior@protonmail.com designates 109.224.244.16 as permitted sender) smtp.mailfrom=darosior@protonmail.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=protonmail.com Received: from mail-24416.protonmail.ch (mail-24416.protonmail.ch. [109.224.244.16]) by gmr-mx.google.com with ESMTPS id d75a77b69052e-5070d6ad345si104661cf.4.2026.02.20.12.38.24 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Feb 2026 12:38:24 -0800 (PST) Received-SPF: pass (google.com: domain of darosior@protonmail.com designates 109.224.244.16 as permitted sender) client-ip=109.224.244.16; Date: Fri, 20 Feb 2026 20:38:17 +0000 To: Bitcoin Development Mailing List From: "'Antoine Poinsot' via Bitcoin Development Mailing List" Subject: [bitcoindev] Extensions to standard tooling for TEMPLATEHASH-CSFS-IK support Message-ID: <9iwKoVRTokGsIwgHzGWO9ptfxAaIpJ_d8JY-uagbNnlKZK0WdUsl53IHO3kG2zcMmPObgDkHDltcVfZg7OAiZ5f11Tbt9e1vDW7GsOy-LeA=@protonmail.com> Feedback-ID: 7060259:user:proton X-Pm-Message-ID: a8c65cd1343a08018ddb6e70d7fe52c018ab1496 MIME-Version: 1.0 Content-Type: text/plain; charset="UTF-8" X-Original-Sender: darosior@protonmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@protonmail.com header.s=protonmail3 header.b=US+tq2BE; spf=pass (google.com: domain of darosior@protonmail.com designates 109.224.244.16 as permitted sender) smtp.mailfrom=darosior@protonmail.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=protonmail.com X-Original-From: Antoine Poinsot Reply-To: Antoine Poinsot Precedence: list Mailing-list: list bitcoindev@googlegroups.com; contact bitcoindev+owners@googlegroups.com List-ID: X-Google-Group-Id: 786775582512 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , X-Spam-Score: -1.0 (-) Hi everyone, Last year Greg Sanders and i presented what we think is a good stopping point in terms of expanding scripting capabilities[^0], and then introduced along with Steven Roose a proposal implementing those capabilities[^1]. I'm following up on this topic today by proposing some extensions to standard tooling to support the new primitives introduced by our proposal. All the additions to the PSBT and Miniscript descriptors specifications described here have been implemented in a proof-of-concept PR to Bitcoin Inquisition[^2], on top of the OP_TEMPLATEHASH implementation[^3]. This is very much exploratory at this stage. I am seeking feedback on my design choices and on whether anything is missing. Let me start with the integration of the new primitives in Miniscript descriptors. This wasn't completely straightforward, since some new capabilities like template hash checks break some invariants, and some primitives like rebindable signatures require additional context. With some adjustment however, all the new capabilities fit reasonably well in this framework. The goal was to enable the following: - ability to use the Taproot internal key as a key fragment in place of hardcoded public keys; - ability to assert that the spending transaction matches a hardcoded template in a given spending path; - ability to check a signature for an arbitrary message in a given spending path; - ability to use a rebindable signature check in place of the regular transaction signature check ('c:' fragment). The Taproot internal key was introduced as a new `pk_i()` fragment, along with a `pki()` alias for `c:pk_i()` in the same vein as `pk()` and `pkh()`. The fragment corresponds to the Bitcoin Script `OP_INTERNALKEY`, has type 'K', type properties 'o', 'n', 'd', 'u', 'k' and malleability properties 's', 'e' (the very same properties as the `pk_k` fragment). Implementing this fragment only introduces a requirement on the Script and string parsers to have access to the Taproot internal key corresponding to the (mini)script being parsed. See the commit message in the PR linked above for the details of how this was done in the Bitcoin Core implementation. Something i think noteworthy is how before the introduction of these primitives, it was always the case that a fragment that has the 's' malleability property ("satisfying this expression always requires a signature") also guaranteed that all spending paths were encumbered by at least one signature check. This in turn limited third-party tempering to the extent permitted by the chosen sighash mode at signing time. Both the Bitcoin Core and Rust-Bitcoin implementations rely on this invariant[^4][^5], using the presence of the 's' property to verify that no spending path lacks a transaction signature check. But some of the new capabilities introduce signature checks (which require access to a private key, and therefore should have the 's' property) that are not over the transaction. And vice-versa, some checks that encumber the spending transactions' outputs, and therefore should make the Script "sane" or "safe to spend" but (arguably) not have the 's' property. Therefore i split the 's' property into 's' (private key knowledge demonstrated) and 't' (all spending paths encumber the spending transaction) as a preparation step for the following fragments. All pre-existing fragment that have the 's' property (`0`, `pk_k()`, `pk_h()`, `multi()`, `multi_a()`, `c:`) also get the 't' property. (nit: the 't' property is technically not really a type property, since no other fragment depend on it, but also not a "satisfaction malleability" property, it's more of a third type of "safety" property. In this writeup i'll use it interchangeably with type properties for the sake of brevity.) A new `th(h)` fragment is introduced. It corresponds to the Script ` OP_TEMPLATEHASH OP_EQUAL`. It is of type 'B', with type properties 'z', 'u', 't' (i.e. encumbers the spending transaction), 'k' and with no (specified) malleability property. The main design decision here was to pass the template hash, and not its preimage, as argument to the `th()` fragment. This is closer in effect to the four hash fragments, while `th()` is conceptually closer to `older()` and `after()` in that it enables limited introspection on the spending transaction. Since the preimage is not necessary to build/parse the Script, and since having a full transaction in the descriptor would be unreasonable anyways, i went with the template hash as the argument. This seems relevant to the discussion of whether we want the descriptor language to encode all (public) information necessary to spend an output, or if it's fine for it to only partially contain that information[^6]. Note that `th()` does not have the 's' malleability property, because we can't assume its satisfaction is not always available, and does not have the 'f' malleability property because, unlike `older()` and `after()`, a dissatisfaction may be available. Up until now, all signing in Miniscript implicitly happened over the spending transaction's sighash. The Miniscript satisfier relied on this invariant to support composable `K`-typed fragments in addition to simpler leaf key fragments (`pk_k`, `pk_h`, and now `pk_i`), by triggering the signing logic directly at the key fragment level, such that the availability of a spending path could be immediately propagated upward the tree, all the way toward the signature-checking fragment. But we are now going to introduce fragments that check a signature against different messages (rebindable signatures, and arbitrary message signatures), so the leaf key fragment needs to have the context of which type of signature is expected. Since there is always exactly 1 signature-checking fragment for N `K`-typed sub-fragments, this context can simply be propagated downward the tree from the signature-checking fragment all the way to the leaf key fragment(s). We introduce a new `cms(X,m)` fragment, which takes a sub-fragment of type `K`, an arbitrarily-sized (within the consensus limits) message `m`, and corresponds to the Script `[X] OP_SWAP OP_CHECKSIGFROMSTACK`. It always has type properties 'u' and 's'. Its type properties 'o', 'n', 'd', 't, 'h', 'i', 'j' and 'k' are equal to that of its sub-fragment. Same for its malleability properties 'f' and 'e'. Interestingly, the order of arguments in BIP 348 is such that an additional `OP_SWAP` is necessary to support composable keys (in place of a hardcoded key expression) in Miniscript. This does not mean that BIP 348 should necessarily be amended, as the Miniscript framework could equally be adapted to support "wrapped key" types (the equivalent of 'W' but for 'K' instead of 'B'). I'm ambivalent about setting the 's' property (which is explicitly set here, but importantly also propagated from the key fragment leaves), because it seems that for this fragment a third party should be able to get ahold of a signature for the arbitrary message more easily than for transaction signature checks. The distinction does not seem quite tractable at the Miniscript level, but always ripping-off the 's' property for this fragment may be a saner default, since a spending path that contains an arbitrary message signature should likely always also contain a transaction signature check. Or maybe a `th()`? In which case it wouldn't get the 's' property at all. At the end of the day this is only about analyzing satisfaction malleability, not correctness, but i am curious what others think about this. Finally, we introduce an 'r:' wrapper, the analog of 'c:' but for rebindable signature checks. It corresponds to the Bitcoin Script `[X] OP_TEMPLATEHASH OP_SWAP OP_CHECKSIGFROMSTACK`. It has type 'B' and takes an argument X of type 'K'. It always has type properties 'u', 's', and 't'. Its type properties 'o', 'n', 'd', 'g', 'h', 'i', 'j' and 'k' are the same as that of its sub-fragment. Same for its malleability properties 's' and 'f'. This is essentially `cms(X,m)` with `m` fixed to the transaction's template hash such that it can have the 't' property (and a neater, 'c:'-like, syntax). Now regarding PSBTs, i think the only extension that really makes sense is to make available information to verify the outputs of a transaction committed in an output via `th()`. Since i expect `cms(X,m)` would be used with `m` set to the hash of the actual message being signed, for obvious onchain efficiency and privacy reasons, or simply because the message is larger than 520 bytes, i considered a PSBT input field that would map arbitrary message hashes to their preimage. But we already have such fields for SHA256/HASH256/RIPEMD160/HASH160 preimages, and i don't really see a reason why not use one of these hash functions, so an extra field seems unnecessary. Similarly, rebindable signatures can simply be provided through the `PSBT_IN_TAP_SCRIPT_SIG` mapping, since the specs already assume that keys are not repeated within a Script anyways. We introduce a new `PSBT_OUT_COMMITTED_TXS` field, which is a mapping from template hash to Bitcoin-serialized transaction. The alternative, as Ademan pointed out in private discussions, is to use a mapping for each field committed to by the template hash (version, locktime, sequences, input index, annex, outputs). This could be a small space saving in case the committed transaction has many inputs, but for smaller transactions the repeated map keys would actually be less efficient. It does have the advantage of not including non-committed fields in the mapping, which could be a footgun in the simpler version. Of course another alternative would be to keep a single mapping and create a custom serialization of only the committed fields to use as value in place of the regular Bitcoin serialization, but i don't think the complexity would be worth it. I'm curious what people think about that. The existing `PSBT_OUT_TAP_INTERNAL_KEY` is not keyed, and therefore may only be used once per output. Since we may want verifiers to be able to inspect the output(s) of transaction(s) committed in this output, we introduce a new `PSBT_OUT_TAP_INTERNAL_KEYS` field. It is a mapping from Taproot output key to Taproot internal key. For the same reason, we introduce a `PSBT_OUT_TAP_TREES` field, which is a mapping from Taproot output key to a list of tuples representing the depth, version and Script for a leaf in a Taproot tree (same format as the value for `PSBT_OUT_TAP_TREE`). Other fields useful to verify the outputs of committed transactions, such as `PSBT_OUT_TAP_BIP32_DERIVATION`, are already keyed and can just be reused directly. Do these extensions to PSBTs and descriptors make sense to support the "Taproot-native (re-)bindable transaction bundle" proposal? Is there anything you think should be included that i'm missing? Best, Antoine Poinsot [^0]: https://gnusha.org/pi/bitcoindev/F5vsDVNGXP_hmCvp4kFnptFLBCXOoRxWk9d05kSInq_kXj0ePqVAJGADkBFJxYIGkjk8Pw1gzBonTivH6WUUb4f6mwNCmJIwdXBMrjjQ0lI=@protonmail.com/ [^1]: https://gnusha.org/pi/bitcoindev/26b96fb1-d916-474a-bd23-920becc3412cn@googlegroups.com/ [^2]: https://github.com/bitcoin-inquisition/bitcoin/pull/108 [^3]: https://github.com/bitcoin-inquisition/bitcoin/pull/100 [^4]: https://github.com/bitcoin/bitcoin/blob/241ad5853bcac94b0fcbe5c67199e5a226da5218/src/script/miniscript.h#L1697 [^5]: https://github.com/rust-bitcoin/rust-miniscript/blob/411b651b7805c781839096832be2ea0e81ed3588/src/miniscript/analyzable.rs#L186-L187 [^6]: To my knowledge this has been discussed a number of times and the latest iteration is https://github.com/bitcoin/bitcoin/issues/24114 -- You received this message because you are subscribed to the Google Groups "Bitcoin Development Mailing List" group. To unsubscribe from this group and stop receiving emails from it, send an email to bitcoindev+unsubscribe@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/bitcoindev/9iwKoVRTokGsIwgHzGWO9ptfxAaIpJ_d8JY-uagbNnlKZK0WdUsl53IHO3kG2zcMmPObgDkHDltcVfZg7OAiZ5f11Tbt9e1vDW7GsOy-LeA%3D%40protonmail.com.