diff options
author | Salvatore Ingala <salvatore.ingala@gmail.com> | 2023-05-02 10:21:01 +0200 |
---|---|---|
committer | bitcoindev <bitcoindev@gnusha.org> | 2023-05-02 08:21:17 +0000 |
commit | 197449274e9351d9ad755d0a4c1e61fde7c0624a (patch) | |
tree | f0ab3997a980b50eccc0d2aacbb5e9ae41a048fa | |
parent | 3bbc4305ac326d4b2d9e98db23e6f7a54b66a9a4 (diff) | |
download | pi-bitcoindev-197449274e9351d9ad755d0a4c1e61fde7c0624a.tar.gz pi-bitcoindev-197449274e9351d9ad755d0a4c1e61fde7c0624a.zip |
Re: [bitcoin-dev] Vaults in the MATT framework
-rw-r--r-- | 29/3d7fd3d9a6937c19e2b31520dfdd6fa8346044 | 992 |
1 files changed, 992 insertions, 0 deletions
diff --git a/29/3d7fd3d9a6937c19e2b31520dfdd6fa8346044 b/29/3d7fd3d9a6937c19e2b31520dfdd6fa8346044 new file mode 100644 index 000000000..b18c9270d --- /dev/null +++ b/29/3d7fd3d9a6937c19e2b31520dfdd6fa8346044 @@ -0,0 +1,992 @@ +Return-Path: <salvatore.ingala@gmail.com> +Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) + by lists.linuxfoundation.org (Postfix) with ESMTP id 4D698C002A + for <bitcoin-dev@lists.linuxfoundation.org>; + Tue, 2 May 2023 08:21:17 +0000 (UTC) +Received: from localhost (localhost [127.0.0.1]) + by smtp2.osuosl.org (Postfix) with ESMTP id 297B040273 + for <bitcoin-dev@lists.linuxfoundation.org>; + Tue, 2 May 2023 08:21:17 +0000 (UTC) +DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 297B040273 +Authentication-Results: smtp2.osuosl.org; + dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com + header.a=rsa-sha256 header.s=20221208 header.b=UBx+0Hcs +X-Virus-Scanned: amavisd-new at osuosl.org +X-Spam-Flag: NO +X-Spam-Score: -2.098 +X-Spam-Level: +X-Spam-Status: No, score=-2.098 tagged_above=-999 required=5 + tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, + DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, + HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, + SPF_PASS=-0.001] autolearn=ham autolearn_force=no +Received: from smtp2.osuosl.org ([127.0.0.1]) + by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) + with ESMTP id Pvi755E0VWiY + for <bitcoin-dev@lists.linuxfoundation.org>; + Tue, 2 May 2023 08:21:14 +0000 (UTC) +X-Greylist: whitelisted by SQLgrey-1.8.0 +DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 7C74940124 +Received: from mail-oo1-xc29.google.com (mail-oo1-xc29.google.com + [IPv6:2607:f8b0:4864:20::c29]) + by smtp2.osuosl.org (Postfix) with ESMTPS id 7C74940124 + for <bitcoin-dev@lists.linuxfoundation.org>; + Tue, 2 May 2023 08:21:14 +0000 (UTC) +Received: by mail-oo1-xc29.google.com with SMTP id + 006d021491bc7-549d9c295dfso2130965eaf.2 + for <bitcoin-dev@lists.linuxfoundation.org>; + Tue, 02 May 2023 01:21:14 -0700 (PDT) +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=gmail.com; s=20221208; t=1683015673; x=1685607673; + h=cc:to:subject:message-id:date:from:in-reply-to:references + :mime-version:from:to:cc:subject:date:message-id:reply-to; + bh=0dwuhCplAaxzMCY0kBTYf5oNeXmixbKwFoYsGjAIN+I=; + b=UBx+0HcsWaDQzoXEmlCqhG3jq+y1bQyLvV2cxGiZ5pTVmjrnIp68BCjjQgOZ8n0rsa + nnO85tyvsmZ60z+IjGgkI18IhooQf/G0bHrVI0GUyRgNKSyqzXzR+vtCr9U1C8jo0N7S + D75wjo+s2o+ouqMnnksO8qfFAvkrpT9+V5ipZcmTZ9REkm7NTEY4cpB3LfQn9COjF1D5 + 6yVgLfbvi72HCR3OhcNwpBYmA8pWDNurWZhYoLP70FhOMQcob6igE3AugIkxFDFnHSfd + 5sIKbJWS+vXAPF9C5mY0qYXGbMcP3QGsbjGClPOYZNviPAyPwWso3pb16EaNWWBpRreX + 058A== +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20221208; t=1683015673; x=1685607673; + h=cc:to:subject:message-id:date:from:in-reply-to:references + :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id + :reply-to; + bh=0dwuhCplAaxzMCY0kBTYf5oNeXmixbKwFoYsGjAIN+I=; + b=eHcIRv3/3xWnO8le2rhDKam+22OTzGHvpiXNGkACATcrhLcP9o16BouPTESURnjhnW + GvyuhF1saX13L2dmE4OuriVfD4pp71sV/Bqe/bin72OXK2LyoCa0coq0oB0L8JY2lMcj + 6NRm9ALTFijIoBEZJYigGoi++Yt6KAXFvK2nNkQxPiyaneLk12OudTAw25kgXWn7+Jyt + P/xlpFOy/+gAXP8RGPdQC0+DungNbVX3ALkIXG/Y3nh2rYXYaUP6Cm3CrV4f3FCjx0d5 + bK6Sz0nrANcUFOBtfpAFIpz6TACLM0nFJ1P2z34SlbuGKkr5oP4i0yfapxL3h9BjGdQ0 + zWcA== +X-Gm-Message-State: AC+VfDx+uQ3r1xIX83zpuhg9vYQB8brpi2lN9upUftvzgMSRuA883kzc + +Z8bYpIDTVgb4LkicQtxNCD5mpSb+cGvKvA3AKd3bBNFlLqq2Q== +X-Google-Smtp-Source: ACHHUZ43iZfYF0SGor/AH/z1EjyZ54mDrR3ha2tMmpg6RFaQRmo8ozXaf2gMUwwY73OLZHfIndppIFwiAkguIMOhnq0= +X-Received: by 2002:a4a:e5d8:0:b0:546:f42b:685b with SMTP id + r24-20020a4ae5d8000000b00546f42b685bmr8238339oov.5.1683015673231; Tue, 02 May + 2023 01:21:13 -0700 (PDT) +MIME-Version: 1.0 +References: <CAMhCMoHEa8vYqm7U9MKFC30_cbCoAJBgoGaP0SCvCXVTyA6TmQ@mail.gmail.com> + <2ApImRS_OSlctWlRLsNykOYE9Z2nEfg8-IUooIluZG2MAVrY9F5oHYi5LBXN7q5QxB2_sLPIVgV-MOUBMEc451HTpPyPdrvog9jPjBpTZ5E=@protonmail.com> +In-Reply-To: <2ApImRS_OSlctWlRLsNykOYE9Z2nEfg8-IUooIluZG2MAVrY9F5oHYi5LBXN7q5QxB2_sLPIVgV-MOUBMEc451HTpPyPdrvog9jPjBpTZ5E=@protonmail.com> +From: Salvatore Ingala <salvatore.ingala@gmail.com> +Date: Tue, 2 May 2023 10:21:01 +0200 +Message-ID: <CAMhCMoFh+Of73RWZ7prRXQB2+_MpsUkf_e+XvTCoawJp6cA-xw@mail.gmail.com> +To: Michael Folkson <michaelfolkson@protonmail.com> +Content-Type: multipart/alternative; boundary="0000000000005abd3905fab19f16" +X-Mailman-Approved-At: Tue, 02 May 2023 08:22:32 +0000 +Cc: Bitcoin Protocol Discussion <bitcoin-dev@lists.linuxfoundation.org> +Subject: Re: [bitcoin-dev] Vaults in the MATT framework +X-BeenThere: bitcoin-dev@lists.linuxfoundation.org +X-Mailman-Version: 2.1.15 +Precedence: list +List-Id: Bitcoin Protocol Discussion <bitcoin-dev.lists.linuxfoundation.org> +List-Unsubscribe: <https://lists.linuxfoundation.org/mailman/options/bitcoin-dev>, + <mailto:bitcoin-dev-request@lists.linuxfoundation.org?subject=unsubscribe> +List-Archive: <http://lists.linuxfoundation.org/pipermail/bitcoin-dev/> +List-Post: <mailto:bitcoin-dev@lists.linuxfoundation.org> +List-Help: <mailto:bitcoin-dev-request@lists.linuxfoundation.org?subject=help> +List-Subscribe: <https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev>, + <mailto:bitcoin-dev-request@lists.linuxfoundation.org?subject=subscribe> +X-List-Received-Date: Tue, 02 May 2023 08:21:17 -0000 + +--0000000000005abd3905fab19f16 +Content-Type: text/plain; charset="UTF-8" +Content-Transfer-Encoding: quoted-printable + +Hi Michael, + +I can't make any claim of expertise on the field (especially on the +other proposals that you mentioned), so this post necessarily includes +my opinions =E2=88=92 and possibly my biases. + +The core functionality of MATT is quite simple, and could be adapted +to any version of the scripting system: basically, COCV allows to +"embed" some data in the next output, and decide its script; CICV +allows "reading" this data. +The design I proposed on taproot is surely not the only possible way, +but it's the most simple/elegant I could come up with. Moreover, it +doesn't seem very useful to spend time trying to get it to work on +pre-taproot Script, due to the obvious advantages of those ideas when +deployed on taproot (like having taptrees, and all the nice properties +of Schnorr signatures). + +CICV/COCV can certainly be considered an additional form of +introspection: you're checking that the script of an input/output +equals a certain value, which is not possible in today's Script. +I think that's generally true for all covenant proposals. + +Unlike some other proposals, MATT is not yet fully formalized, so I +generally call "MATT" the combination of CICV+COCV, plus some other +small set of opcodes that is yet to be defined exactly. I would say it +fits in the same family as APO/OP_CTV/OP_VAULT, per your bucketization. + +The previous posts about MATT, fraud proofs, etc. are an exploration of +the deeper things that are enabled by the MATT opcodes. The claim is +that a set of changes that is (arguably) quite small and easy to analyze +is enough to express general smart contracts =E2=88=92 thanks to fraud proo= +fs. +However, fraud proofs themselves are a quite advanced application of +the new opcodes, and are not needed for most/all of the things that +people are trying to build today with the other covenant proposals. + + +Since you mention Simplicity: my current understanding is that its +endeavour of replacing Script with a better language is orthogonal to +the discussion about what features (e.g.: introspection, covenants) +should be in the language. + +All the covenant proposals listed above are technically a lot smaller +and easier to audit than both the SegWit and the Taproot soft forks, +both in terms of code and conceptual complexity. + +Therefore, if we _do_ want the features that they enable, the required +engineering for a soft-fork is relatively straightforward, and there is +not much of a reason to wait for Simplicity. It will be trivial to "port" +any +constructions we might create today with covenants to Simplicity scripts. + +If we _do not_ want those features, then the decision would rather be +guided by other considerations, like potential risks to bitcoin caused +by the effect of those features on miners' incentives. These +concerns are not answered by Simplicity, as far as I understand: +you would then want to implement Simplicity _without_ those features. + +Best, +Salvatore + +On Mon, 1 May 2023 at 16:18, Michael Folkson <michaelfolkson@protonmail.com= +> +wrote: + +> Hi Salvatore +> +> Can you clarify for me which bucket this proposal sits? We have APO, CTV, +> OP_VAULT etc that are proposals to add additional functionality to SegWit +> version 1, Tapleaf version 0 scripts. We have Simplicity that would need = +a +> new Tapleaf version (e.g. Tapleaf version 1). And then there are CISA lik= +e +> proposals that would need a new SegWit version (e.g. SegWit version 2). I= +t +> looks to me like your proposal is in the first bucket (same as APO, CTV +> etc) as it is just introducing new opcode functionality to existing scrip= +t +> with no deeper introspection needed but previous and current discussion o= +f +> fraud proofs, MATT frameworks etc made me initially think it was going to +> require more than that. +> +> Thanks +> Michael +> +> -- +> Michael Folkson +> Email: michaelfolkson at protonmail.com +> GPG: A2CF5D71603C92010659818D2A75D601B23FEE0F +> +> Learn about Bitcoin: https://www.youtube.com/@portofbitcoin +> +> ------- Original Message ------- +> On Monday, April 24th, 2023 at 20:37, Salvatore Ingala via bitcoin-dev < +> bitcoin-dev@lists.linuxfoundation.org> wrote: +> +> Hello list, +> +> TL;DR: the core opcodes of MATT can build vaults with a very similar desi= +gn +> to OP_VAULT. Code example here: +> +> +> https://github.com/bitcoin-inquisition/bitcoin/compare/24.0...bigspider:b= +itcoin-inquisition:matt-vault +> +> +> In my previous emails about the MATT proposal for smart contracts in +> bitcoin [1], I mostly focused on proving its generality; that is, it +> allows arbitrary smart contracts thanks to fraud proofs. +> +> While I still find this "completeness" result compelling, I spent more ti= +me +> thinking about the framework itself; the construction is not very +> interesting +> if it turns simple things into complicated ones. Luckily, this is not the +> case. +> In particular, in this email we will not merkleize anything (other than +> taptrees). +> +> This post describes some progress into formalizing the semantics of the +> core +> opcodes, and demonstrates how they could be used to create vaults that se= +em +> comparable to the ones built with OP_VAULT [2], despite using general +> purpose +> opcodes. +> +> An implementation and some minimal tests matching the content of this +> e-mail can be found in the link above, using the bitcoin-inquisition as t= +he +> base branch. +> +> Note that the linked code is not well tested and is only intended for +> exploratory and demonstrative purposes; therefore, bugs are likely at thi= +s +> stage. +> +> +> ########################## +> # PART 1: MATT's core +> ########################## +> +> In this section, I will discuss plausible semantics for the core opcodes +> for MATT. +> +> The two core opcodes are defined below as OP_CHECKINPUTCONTRACTVERIFY and +> OP_CHECKOUTPUTCONTRACTVERIFY. +> +> (the initial posts named them OP_CHECK{INPUT,OUTPUT}COVENANTVERIFY) +> +> They enhance Script with the following capabilities: +> - decide the taptree of the output +> - embed some (dynamically computed) data in the output +> - access the embedded data in the current UTXO (if any) +> +> The opcodes below are incomplete, as they only control the output's Scrip= +t +> and +> not the amounts; more on that below. +> +> Other than that, the semantics should be quite close to the "right" one f= +or +> the MATT framework. +> +> +> ### The opcodes +> +> case OP_CHECKINPUTCONTRACTVERIFY: +> { +> // OP_CHECKINPUTCONTRACTVERIFY is only available in Tapscript +> if (sigversion =3D=3D SigVersion::BASE || sigversion =3D=3D +> SigVersion::WITNESS_V0) return set_error(serror, SCRIPT_ERR_BAD_OPCODE); +> // (x d -- ) +> if (stack.size() < 2) +> return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); +> valtype& x =3D stacktop(-2); +> valtype& d =3D stacktop(-1); +> if (x.size() !=3D 32 || d.size() !=3D 32) +> return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); +> const XOnlyPubKey nakedXOnlyKey{Span<const unsigned char>{x.data(), +> x.data() + 32}}; +> const uint256 data(d); +> if (!execdata.m_internal_key.has_value()) +> return set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); // TODO +> // Verify that tweak(lift_x(x), d) equals the internal pubkey +> if (!execdata.m_internal_key.value().CheckDoubleTweak(nakedXOnlyKey, +> &data, nullptr)) +> return set_error(serror, SCRIPT_ERR_WRONGCONTRACTDATA); +> popstack(stack); +> popstack(stack); +> } +> break; +> case OP_CHECKOUTPUTCONTRACTVERIFY: +> { +> // OP_CHECKOUTPUTCONTRACTVERIFY is only available in Tapscript +> if (sigversion =3D=3D SigVersion::BASE || sigversion =3D=3D +> SigVersion::WITNESS_V0) return set_error(serror, SCRIPT_ERR_BAD_OPCODE); +> // (out_i x taptree d -- ) +> if (stack.size() < 4) +> return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); +> int out_i =3D CScriptNum(stacktop(-4), fRequireMinimal).getint(); +> valtype& x =3D stacktop(-3); +> valtype& taptree =3D stacktop(-2); +> valtype& d =3D stacktop(-1); +> auto outps =3D checker.GetTxvOut(); +> // Return error if the evaluation context is unavailable +> if (!outps) +> return set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); // TODO +> if (x.size() !=3D 32 || taptree.size() !=3D 32 || (d.size() !=3D 0 && d.s= +ize() +> !=3D 32)) +> return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); +> if (out_i < 0 || out_i >=3D (int)outps->size()) +> return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); +> const XOnlyPubKey nakedXOnlyKey{Span<const unsigned char>{x.data(), +> x.data() + 32}}; +> const uint256 data(d); +> const uint256 *data_ptr =3D (d.size() =3D=3D 0 ? nullptr : &data); +> const uint256 merkle_tree(taptree); +> CScript scriptPubKey =3D outps->at(out_i).scriptPubKey; +> if (scriptPubKey.size() !=3D 1 + 1 + 32 || scriptPubKey[0] !=3D OP_1 || +> scriptPubKey[1] !=3D 32) +> return set_error(serror, SCRIPT_ERR_WRONGCONTRACTDATA); +> const XOnlyPubKey outputXOnlyKey{Span<const unsigned +> char>{scriptPubKey.data() + 2, scriptPubKey.data() + 34}}; +> // Verify that taptweak(tweak(lift_x(x), d), taptree) equals the internal +> pubkey +> if (!outputXOnlyKey.CheckDoubleTweak(nakedXOnlyKey, data_ptr, +> &merkle_tree)) +> return set_error(serror, SCRIPT_ERR_WRONGCONTRACTDATA); +> popstack(stack); +> popstack(stack); +> popstack(stack); +> popstack(stack); +> } +> break; +> +> ### Commentary +> +> CheckDoubleTweak function (implemented in the branch) gets an x-only +> pubkey, +> optionally some data, and optionally taptree's merkle root. +> It verifies that the x-only pubkey being tested equals the given naked +> pubkey, +> optionally tweaked with the embedded data, optionally tweaked with the +> tagged +> hash of the merkle tree per BIP-0341 [3]. +> Making both the tweaks optional allows to simplify the code, and also to +> obtain +> more compact scripts in some spending paths. +> +> In words: +> +> - OP_CHECKINPUTCONTRACTVERIFY: verify that the current input's internal k= +ey +> contains some embedded data (which would typically be passed through the +> witness stack) +> - OP_CHECKOUTPUTCONTRACTVERIFY: verify that a given output is a certain +> P2TR +> output script containing the desired embedded data. +> +> TBD if the tweaking used for the embedded data tweak should use a tagged +> hash; +> omitted for simplicity in this demo implementation. +> +> ### Amount preservation +> +> In the code above and in the linked demo implementation, the opcodes only +> operate on the scriptPubkey; a complete implementation would want to make +> sure +> that amounts are correctly preserved. +> +> The most direct and general way to address this would be to allow direct +> introspection on the output amounts. This has the complication that outpu= +t +> amounts require 64-bits arithmetics, as discussed in the context of other +> proposals, for example: [4]. +> +> One more limited approach that works well for many interesting contracts +> is that of the deferred checks, implemented in OP_VAULT [2]. +> The idea is that all the amounts of the inputs that commit to the same +> output +> script with OP_CHECKOUTPUTCONTRACTVERIFY are added together, and the scri= +pt +> interpreter requires that the amount of that output is not smaller than t= +he +> total amount of those inputs. This check is therefore transaction-wide +> rather +> than being tested during the input's script evaluation. +> +> This behaviour is adequate for vaults and likely suitable for many other +> applications; however, it's not the most general approach. I didn't try t= +o +> implement it yet, and defer the decision on the best approach to a later +> time. +> +> ### Extensions +> +> The opcodes above are not enough for the full generality of MATT: one wou= +ld +> need to add an opcode like OP_SHA256CAT to allow the data embedding to +> commit +> to multiple pieces of data. +> This is not used in today's post, therefore I left it out of these code +> examples. +> +> It would be easy to extend OP_CHECKOUTPUTCONTRACTVERIFY to also apply for +> an arbitrary input (typically, different from the currently executed one)= +; +> there +> are likely use cases for that, allowing to define contracts with more +> complex +> cross-input semantics, but I preferred to keep things simple. +> +> Of course, one could also entirely replace CICV/COCV with generic full +> introspection on inputs/output's program, plus opcodes for elliptic curve +> math +> and tagged hashes. +> +> +> ########################## +> # PART 2: Vaults with MATT +> ########################## +> +> In the rest of this post, I will document the first attempt at creating a +> vault +> using the opcodes described. +> +> While not an attempt at cloning exactly the functionality of OP_VAULT [2]= +, +> it borrows heavily from the excellent work that was done there. +> +> In particular, it also inherits the choice of using OP_CTV as a primitive= +, +> building on top of the bitcoin-inquisition's current branch that has +> already +> merged OP_CTV. Reasonable vaults would be possible without CTV, but they +> would be less efficient, particularly in the case of sending to many +> addresses +> in a single unvaulting flow. +> +> ### Distilling OP_VAULT +> +> Abstracting from the implementation details, I mentally model a vault as = +a +> simple state machine with 2 states: [V] and [U]: +> +> [V]: the initial vault UTXO(s); +> [U]: the utxo produced by the "trigger transaction" during unvaulting. +> +> On the typical path: one or more [V] UTXOs are sent to the [U] state, and +> after +> a timelock set on [U] expires, [U] is spent to one or several destination= +s. +> Crucially, the destination outputs and amounts are already decided when +> [V] is +> spent into [U]. +> +> At any time before the funds are spent from [U], they can always be spent +> by +> sending them to some specified recovery path. +> +> There are two key elements that are part of OP_VAULT's semantics, and +> could be +> generalized: +> +> =E2=88=92 Forcing the script/amount of the next stepon +> =E2=88=92 Storing some data for future Script's access (in the vault's ca= +se, a hash +> that commits to the final withdrawal transaction). +> +> CICV/COCV generalize both to arbitrary scripts (taptrees) and state +> machines, +> and to dynamical and witness-dependent data embedded in the pubkey of a +> P2TR +> output. +> +> ### Vault parameters +> +> A contract that represents a vault has the following parameters (hardcode= +d +> in +> the script when the vault is created): +> +> - alternate_pk: a key that can be used any time. +> - spend_delay: the relative timelock before the withdrawal can be +> finalized; +> - recover_pk: a pubkey for a P2TR output where funds can be sent at any +> time. +> +> The alternate_pk is a pubkey that can optionally be used as the key-path +> spending condition for both states [V] and [U]. If such a spending +> condition is not +> desired, it can be replaced with a NUMS point, making the key-path +> unspendable. +> +> The spend_delay is the number of blocks that must be mined before the fin= +al +> withdrawal transaction +> +> In this example we also use an unvault_pk needed to authorize the +> unvaulting +> process (that is, spend [V] into [U]); this could be replaced with any +> miniscript +> or other conditions expressible in Script. +> +> ### P2TR structure for [V] (vault) +> +> internal key: alternate_pk +> +> Script 1: "trigger" +> # witness: <out_i> <ctv-hash> +> { +> <alternate_pk>, +> <merkle root of U's taptree>, +> 2, OP_ROLL, +> OP_CHECKOUTPUTCONTRACTVERIFY, +> +> <unvault_pk> +> OP_CHECKSIG +> } +> +> Script 2: "recover" +> # witness: <out_i> +> { +> recover_pk, +> OP_0, # no data tweak +> OP_0, # no taptweak +> OP_CHECKOUTPUTCONTRACTVERIFY, +> OP_TRUE +> } +> +> The "trigger" script requires in the witness an output index and the +> ctv-hash +> that describes the withdrawal transaction. +> COCV forces the output to contain the ctv-hash as embedded data. +> That's followed by the unvaulting condition =E2=88=92 in this example, a = +simple +> signature check. +> +> The "recover" script doesn't require any signature, and it simply forces +> the output specified in the witness to be a P2TR output with recover_pk a= +s +> its +> pubkey. +> +> (Omitting the "recover" script in [V] would reduce the size of the witnes= +s +> by +> 32 bytes in the expected case, and might be preferred for some users) +> +> ### P2TR structure for [U] (unvaulting state) +> +> internal key: alternate_pk (tweaked with ctv_hash) +> +> Script 1: "withdrawal" +> # witness: <ctv_hash> +> { +> OP_DUP, +> +> # check that the top of the stack is the +> # embedded data in the current input +> <alternate_pk>, OP_SWAP, +> OP_CHECKINPUTCONTRACTVERIFY, +> +> # Check timelock +> <spend_delay>, +> OP_CHECKSEQUENCEVERIFY, +> OP_DROP, +> +> # Check that the transaction output is as expected +> OP_CHECKTEMPLATEVERIFY +> } +> +> Script 2: "recover" +> # witness: <out_i> +> { +> <recover_pk>, +> OP_0, +> OP_0, +> OP_CHECKOUTPUTCONTRACTVERIFY, +> OP_TRUE +> } +> +> The "withdrawal" finalizes the transaction, by checking that the timelock +> expired and +> the outputs satisfy the CTV hash that was committed to in the previous +> transaction. +> +> The "recover" script is identical as before. +> +> +> ### Differences with OP_VAULT vaults +> +> Here I refer to the latest version of OP_VAULT at the time of writing. [5= +] +> It is not a thorough analysis. +> +> Unlike the implementation based on OP_VAULT, the [V] utxos don't have an +> option +> to add an additional output that is sent back to the same exact vault. +> Supporting this use case seems to require a more general way of handling +> the +> distribution of amounts than what I discussed in the section above: that +> would +> in fact need to be generalized to the case of multiple +> OP_CHECKOUTPUTCONTRACTVERIFY opcodes executed for the same input. +> +> By separating the ctv-hash (which is considered "data") from the scripts +> in the +> taptree, one entirely avoids the need to dynamically create taptrees and +> replace leaves in the covenant-encumbered UTXOs; in fact, the taptrees of +> [V] +> and [U] are already set in stone when [V] utxos are created, and only the +> "data" portion of [U]'s scriptPubKey is dynamically computed. In my +> opinion, +> this makes it substantially easier to program "state machines" that +> control the +> behavior of coins, of which vaults are a special case. +> +> I hope you'll find this interesting, and look forward to your comments. +> +> Salvatore Ingala +> +> +> [1] - +> https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-November/021= +223.html +> [2] - https://github.com/bitcoin/bips/pull/1421 +> [3] - https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki +> [4] - +> https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-September/01= +9420.html +> [5] - +> https://github.com/bitcoin/bips/blob/7112f308b356cdf0c51d917dbdc1b98e3062= +1f80/bip-0345.mediawiki +> +> +> + +--0000000000005abd3905fab19f16 +Content-Type: text/html; charset="UTF-8" +Content-Transfer-Encoding: quoted-printable + +<div dir=3D"ltr">Hi Michael,<br><br>I can't make any claim of expertise= + on the field (especially on the<br>other proposals that you mentioned), so= + this post necessarily includes<br>my opinions =E2=88=92 and possibly my bi= +ases.<br><br>The core functionality of MATT is quite simple, and could be a= +dapted<br>to any version of the scripting system: basically, COCV allows to= +<br>"embed" some data in the next output, and decide its script; = +CICV<br>allows "reading" this data.<br>The design I proposed on t= +aproot is surely not the only possible way,<br>but it's the most simple= +/elegant I could come up with. Moreover, it<br>doesn't seem very useful= + to spend time trying to get it to work on<br>pre-taproot Script, due to th= +e obvious advantages of those ideas when<br>deployed on taproot (like havin= +g taptrees, and all the nice properties<br>of Schnorr signatures).<br><br>C= +ICV/COCV can certainly be considered an additional form of<br>introspection= +: you're checking that the script of an input/output<br>equals a certai= +n value, which is not possible in today's Script.<br>I think that's= + generally true for all covenant proposals.<br><br>Unlike some other propos= +als, MATT is not yet fully formalized, so I<br>generally call "MATT&qu= +ot; the combination of CICV+COCV, plus some other<br>small set of opcodes t= +hat is yet to be defined exactly. I would say it<br>fits in the same family= + as APO/OP_CTV/OP_VAULT, per your bucketization.<br><br>The previous posts = +about MATT, fraud proofs, etc. are an exploration of<br>the deeper things t= +hat are enabled by the MATT opcodes. The claim is<br>that a set of changes = +that is (arguably) quite small and easy to analyze<br>is enough to express = +general smart contracts =E2=88=92 thanks to fraud proofs.<br>However, fraud= + proofs themselves are a quite advanced application of<div>the new opcodes,= + and are not needed for most/all of the things that</div><div>people are tr= +ying to build today with the other covenant proposals.<br><br><br>Since you= + mention Simplicity: my current understanding is that its<br>endeavour of r= +eplacing Script with a better language is orthogonal to<br>the discussion a= +bout what features (e.g.: introspection, covenants)</div><div>should be in = +the language.<br><br>All the covenant proposals listed above are technicall= +y a lot smaller<br>and easier to audit than both the SegWit and the Taproot= + soft forks,<br>both in terms of code and conceptual complexity.<br><br>The= +refore, if we _do_ want the features that they enable, the required<br>engi= +neering for a soft-fork is relatively straightforward, and there is<br>not = +much of a reason to wait for Simplicity. It will be trivial to "port&q= +uot; any</div><div>constructions we might create today with covenants to Si= +mplicity scripts.</div><div><br>If we _do not_ want those features, then th= +e decision would rather be<br>guided by other considerations, like potentia= +l risks to bitcoin caused<br>by the effect of those features on miners'= + incentives. These<br>concerns are not answered by Simplicity, as far as I = +understand:</div><div>you would then want to implement Simplicity _without_= + those features.<br><br>Best,<br>Salvatore<br></div></div><br><div class=3D= +"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr">On Mon, 1 May 2023 at 1= +6:18, Michael Folkson <<a href=3D"mailto:michaelfolkson@protonmail.com">= +michaelfolkson@protonmail.com</a>> wrote:<br></div><blockquote class=3D"= +gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(20= +4,204,204);padding-left:1ex"><div style=3D"font-family:Arial,sans-serif;fon= +t-size:14px">Hi Salvatore</div><div style=3D"font-family:Arial,sans-serif;f= +ont-size:14px"><br></div><div style=3D"font-family:Arial,sans-serif;font-si= +ze:14px">Can you clarify for me which bucket this proposal sits? We have AP= +O, CTV, OP_VAULT etc that are proposals to add additional functionality to = +SegWit version 1, Tapleaf version 0 scripts. We have Simplicity that would = +need a new Tapleaf version (e.g. Tapleaf version 1). And then there are CIS= +A like proposals that would need a new SegWit version (e.g. SegWit version = +2). It looks to me like your proposal is in the first bucket (same as APO, = +CTV etc) as it is just introducing new opcode functionality to existing scr= +ipt with no deeper introspection needed but previous and current discussion= + of fraud proofs, MATT frameworks etc made me initially think it was going = +to require more than that.</div><div style=3D"font-family:Arial,sans-serif;= +font-size:14px"><br></div><div style=3D"font-family:Arial,sans-serif;font-s= +ize:14px">Thanks</div><div style=3D"font-family:Arial,sans-serif;font-size:= +14px">Michael</div><div style=3D"font-family:Arial,sans-serif;font-size:14p= +x"><br></div> +<div style=3D"font-family:Arial,sans-serif;font-size:14px"> + <div> + <div style=3D"font-family:arial;font-size:14px"><span style=3D"colo= +r:rgb(38,42,51);font-style:normal;font-weight:400;letter-spacing:normal;tex= +t-indent:0px;text-transform:none;white-space:pre-wrap;word-spacing:0px;back= +ground-color:rgb(255,255,255);float:none;display:inline"><span style=3D"fon= +t-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo,monospac= +e,monospace"><span style=3D"font-size:14px">--<br>Michael Folkson</span></s= +pan></span></div><div style=3D"font-family:arial;font-size:14px"><span styl= +e=3D"color:rgb(38,42,51);font-style:normal;font-weight:400;letter-spacing:n= +ormal;text-indent:0px;text-transform:none;white-space:pre-wrap;word-spacing= +:0px;background-color:rgb(255,255,255);float:none;display:inline"><span sty= +le=3D"font-family:SFMono-Regular,Consolas,"Liberation Mono",Menlo= +,monospace,monospace"><span style=3D"font-size:14px">Email: michaelfolkson = +at </span></span></span><a href=3D"http://protonmail.com/" style=3D"line-he= +ight:normal;text-decoration:underline;font-family:SFMono-Regular,Consolas,&= +quot;Liberation Mono",Menlo,monospace,monospace;font-size:14px;font-st= +yle:normal;font-weight:400;letter-spacing:normal;text-indent:0px;text-trans= +form:none;white-space:pre-wrap;word-spacing:0px" rel=3D"noopener noreferrer= +" target=3D"_blank">protonmail.com</a><span style=3D"color:rgb(38,42,51);fo= +nt-style:normal;font-weight:400;letter-spacing:normal;text-indent:0px;text-= +transform:none;white-space:pre-wrap;word-spacing:0px;background-color:rgb(2= +55,255,255);float:none;display:inline"><span style=3D"font-family:SFMono-Re= +gular,Consolas,"Liberation Mono",Menlo,monospace,monospace"><span= + style=3D"font-size:14px"> </span></span></span></div><div style=3D"font-fa= +mily:arial;font-size:14px"><span style=3D"color:rgb(38,42,51);font-style:no= +rmal;font-weight:400;letter-spacing:normal;text-indent:0px;text-transform:n= +one;white-space:pre-wrap;word-spacing:0px;background-color:rgb(255,255,255)= +;float:none;display:inline"><span style=3D"font-family:SFMono-Regular,Conso= +las,"Liberation Mono",Menlo,monospace,monospace"><span style=3D"f= +ont-size:14px">GPG: <span>A2CF5D71603C92010659818D2A75D601B23FEE0F</span></= +span></span></span></div><div style=3D"font-family:arial;font-size:14px"><s= +pan style=3D"color:rgb(38,42,51);font-style:normal;font-weight:400;letter-s= +pacing:normal;text-indent:0px;text-transform:none;white-space:pre-wrap;word= +-spacing:0px;background-color:rgb(255,255,255);float:none;display:inline"><= +span style=3D"font-family:SFMono-Regular,Consolas,"Liberation Mono&quo= +t;,Menlo,monospace,monospace"><span style=3D"font-size:14px"><span><br></sp= +an></span></span></span></div><div style=3D"font-family:arial;font-size:14p= +x"><span style=3D"color:rgb(38,42,51);font-style:normal;font-weight:400;let= +ter-spacing:normal;text-indent:0px;text-transform:none;white-space:pre-wrap= +;word-spacing:0px;background-color:rgb(255,255,255);float:none;display:inli= +ne"><span style=3D"font-family:SFMono-Regular,Consolas,"Liberation Mon= +o",Menlo,monospace,monospace"><span style=3D"font-size:14px"><span>Lea= +rn about Bitcoin: <span><a href=3D"https://www.youtube.com/@portofbitcoin" = +rel=3D"noopener noreferrer" target=3D"_blank">https://www.youtube.com/@port= +ofbitcoin</a></span></span></span></span></span></div> + </div> + =20 + <div> + =20 + </div> +</div> +<div style=3D"font-family:Arial,sans-serif;font-size:14px"><br></div><div> + ------- Original Message -------<br> + On Monday, April 24th, 2023 at 20:37, Salvatore Ingala via bitcoin-= +dev <<a href=3D"mailto:bitcoin-dev@lists.linuxfoundation.org" target=3D"= +_blank">bitcoin-dev@lists.linuxfoundation.org</a>> wrote:<br><br> + <blockquote type=3D"cite"> + <div dir=3D"ltr">Hello list,<br><br>TL;DR: the core opcodes of = +MATT can build vaults with a very similar design<br>to OP_VAULT. Code examp= +le here:<br><br> <a href=3D"https://github.com/bitcoin-inquisition/bitcoin/= +compare/24.0...bigspider:bitcoin-inquisition:matt-vault" rel=3D"noreferrer = +nofollow noopener" target=3D"_blank"> https://github.com/bitcoin-inquisitio= +n/bitcoin/compare/24.0...bigspider:bitcoin-inquisition:matt-vault</a><br><b= +r><br>In my previous emails about the MATT proposal for smart contracts in<= +br>bitcoin [1], I mostly focused on proving its generality; that is, it<br>= +allows arbitrary smart contracts thanks to fraud proofs.<br><br>While I sti= +ll find this "completeness" result compelling, I spent more time<= +br>thinking about the framework itself; the construction is not very intere= +sting<br>if it turns simple things into complicated ones. Luckily, this is = +not the case.<br>In particular, in this email we will not merkleize anythin= +g (other than taptrees).<br><br>This post describes some progress into form= +alizing the semantics of the core<br>opcodes, and demonstrates how they cou= +ld be used to create vaults that seem<br>comparable to the ones built with = +OP_VAULT [2], despite using general purpose<br>opcodes.<br><br>An implement= +ation and some minimal tests matching the content of this<br>e-mail can be = +found in the link above, using the bitcoin-inquisition as the<br>base branc= +h.<br><br>Note that the linked code is not well tested and is only intended= + for<br>exploratory and demonstrative purposes; therefore, bugs are likely = +at this<br>stage.<br><br><br>##########################<br># PART 1: MAT= +T's core<br>##########################<br><br>In this section, I will d= +iscuss plausible semantics for the core opcodes for MATT.<br><br>The two co= +re opcodes are defined below as OP_CHECKINPUTCONTRACTVERIFY and<br>OP_CHECK= +OUTPUTCONTRACTVERIFY.<br><br>(the initial posts named them OP_CHECK{INPUT,O= +UTPUT}COVENANTVERIFY)<br><br>They enhance Script with the following capabil= +ities:<br> - decide the taptree of the output<br> - embed some (dynamical= +ly computed) data in the output<br> - access the embedded data in the curr= +ent UTXO (if any)<br><br>The opcodes below are incomplete, as they only con= +trol the output's Script and<br>not the amounts; more on that below.<br= +><br>Other than that, the semantics should be quite close to the "righ= +t" one for<br>the MATT framework.<br><br><br>### The opcodes<br><br><f= +ont face=3D"monospace">case OP_CHECKINPUTCONTRACTVERIFY:<br>{<br> // OP_= +CHECKINPUTCONTRACTVERIFY is only available in Tapscript<br> if (sigversi= +on =3D=3D SigVersion::BASE || sigversion =3D=3D SigVersion::WITNESS_V0) ret= +urn set_error(serror, SCRIPT_ERR_BAD_OPCODE);<br> // (x d -- )<br> if= + (stack.size() < 2)<br> return set_error(serror, SCRIPT_ERR_INVAL= +ID_STACK_OPERATION);<br> valtype& x =3D stacktop(-2);<br> valtype= +& d =3D stacktop(-1);<br> if (x.size() !=3D 32 || d.size() !=3D 32)<= +br> return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);<br= +> const XOnlyPubKey nakedXOnlyKey{Span<const unsigned char>{x.data= +(), x.data() + 32}};<br> const uint256 data(d);<br> if (!execdata.m_i= +nternal_key.has_value())<br> return set_error(serror, SCRIPT_ERR_UNK= +NOWN_ERROR); // TODO<br> // Verify that tweak(lift_x(x), d) equals the = +internal pubkey<br> if (!execdata.m_internal_key.value().CheckDoubleTwea= +k(nakedXOnlyKey, &data, nullptr))<br> return set_error(serror, S= +CRIPT_ERR_WRONGCONTRACTDATA);<br> popstack(stack);<br> popstack(stack= +);<br>}<br>break;<br>case OP_CHECKOUTPUTCONTRACTVERIFY:<br>{<br> // OP_C= +HECKOUTPUTCONTRACTVERIFY is only available in Tapscript<br> if (sigversi= +on =3D=3D SigVersion::BASE || sigversion =3D=3D SigVersion::WITNESS_V0) ret= +urn set_error(serror, SCRIPT_ERR_BAD_OPCODE);<br> // (out_i x taptree d = +-- )<br> if (stack.size() < 4)<br> return set_error(serror, SC= +RIPT_ERR_INVALID_STACK_OPERATION);<br> int out_i =3D CScriptNum(stacktop= +(-4), fRequireMinimal).getint();<br> valtype& x =3D stacktop(-3);<br= +> valtype& taptree =3D stacktop(-2);<br> valtype& d =3D stack= +top(-1);<br> auto outps =3D checker.GetTxvOut();<br> // Return error = +if the evaluation context is unavailable<br> if (!outps)<br> retu= +rn set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); // TODO<br> if (x.size()= + !=3D 32 || taptree.size() !=3D 32 || (d.size() !=3D 0 && d.size() = +!=3D 32))<br> return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPER= +ATION);<br> if (out_i < 0 || out_i >=3D (int)outps->size())<br>= + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);<br> = + const XOnlyPubKey nakedXOnlyKey{Span<const unsigned char>{x.data(),= + x.data() + 32}};<br> const uint256 data(d);<br> const uint256 *data_= +ptr =3D (d.size() =3D=3D 0 ? nullptr : &data);<br> const uint256 mer= +kle_tree(taptree);<br> CScript scriptPubKey =3D outps->at(out_i).scri= +ptPubKey;<br> if (scriptPubKey.size() !=3D 1 + 1 + 32 || scriptPubKey[0]= + !=3D OP_1 || scriptPubKey[1] !=3D 32)<br> return set_error(serror, = +SCRIPT_ERR_WRONGCONTRACTDATA);<br> const XOnlyPubKey outputXOnlyKey{Span= +<const unsigned char>{scriptPubKey.data() + 2, scriptPubKey.data() + = +34}};<br> // Verify that taptweak(tweak(lift_x(x), d), taptree) equals t= +he internal pubkey<br> if (!outputXOnlyKey.CheckDoubleTweak(nakedXOnlyKe= +y, data_ptr, &merkle_tree))<br> return set_error(serror, SCRIPT_= +ERR_WRONGCONTRACTDATA);<br> popstack(stack);<br> popstack(stack);<br>= + popstack(stack);<br> popstack(stack);<br>}<br>break;</font><br><br>#= +## Commentary<br><br>CheckDoubleTweak function (implemented in the branch) = +gets an x-only pubkey,<br>optionally some data, and optionally taptree'= +s merkle root.<br>It verifies that the x-only pubkey being tested equals th= +e given naked pubkey,<br>optionally tweaked with the embedded data, optiona= +lly tweaked with the tagged<br>hash of the merkle tree per BIP-0341 [3].<di= +v>Making both the tweaks optional allows to simplify the code, and also to = +obtain</div><div>more compact scripts in some spending paths.<br><br>In wor= +ds:<br><br>- OP_CHECKINPUTCONTRACTVERIFY: verify that the current input'= +;s internal key<br> contains some embedded data (which would typically be = +passed through the<br> witness stack)<br>- OP_CHECKOUTPUTCONTRACTVERIFY: v= +erify that a given output is a certain P2TR<br> output script containing t= +he desired embedded data.<br><br>TBD if the tweaking used for the embedded = +data tweak should use a tagged hash;<br>omitted for simplicity in this demo= + implementation.<br><br>### Amount preservation<br><br>In the code above an= +d in the linked demo implementation, the opcodes only<br>operate on the scr= +iptPubkey; a complete implementation would want to make sure<br>that amount= +s are correctly preserved.<br><br>The most direct and general way to addres= +s this would be to allow direct<br>introspection on the output amounts. Thi= +s has the complication that output<br>amounts require 64-bits arithmetics, = +as discussed in the context of other<br>proposals, for example: [4].<br><br= +>One more limited approach that works well for many interesting contracts<b= +r>is that of the deferred checks, implemented in OP_VAULT [2].<br>The idea = +is that all the amounts of the inputs that commit to the same output<br>scr= +ipt with OP_CHECKOUTPUTCONTRACTVERIFY are added together, and the script<br= +>interpreter requires that the amount of that output is not smaller than th= +e<br>total amount of those inputs. This check is therefore transaction-wide= + rather<br>than being tested during the input's script evaluation.<br><= +br>This behaviour is adequate for vaults and likely suitable for many other= +<br>applications; however, it's not the most general approach. I didn&#= +39;t try to<br>implement it yet, and defer the decision on the best approac= +h to a later time.<br><br>### Extensions<br><br>The opcodes above are not e= +nough for the full generality of MATT: one would<br>need to add an opcode l= +ike OP_SHA256CAT to allow the data embedding to commit<br>to multiple piece= +s of data.<br>This is not used in today's post, therefore I left it out= + of these code examples.<br><br>It would be easy to extend OP_CHECKOUTPUTCO= +NTRACTVERIFY to also apply for<br>an arbitrary input (typically, different = +from the currently executed one); there<br>are likely use cases for that, a= +llowing to define contracts with more complex<br>cross-input semantics, but= + I preferred to keep things simple.<br><br>Of course, one could also entire= +ly replace CICV/COCV with generic full<br>introspection on inputs/output= +9;s program, plus opcodes for elliptic curve math<br>and tagged hashes.<br>= +<br><br>##########################<br># PART 2: Vaults with MATT<br>####= +######################<br><br>In the rest of this post, I will document the= + first attempt at creating a vault<br>using the opcodes described.<br><br>W= +hile not an attempt at cloning exactly the functionality of OP_VAULT [2],<b= +r>it borrows heavily from the excellent work that was done there.<br><br>In= + particular, it also inherits the choice of using OP_CTV as a primitive,<br= +>building on top of the bitcoin-inquisition's current branch that has a= +lready<br>merged OP_CTV. Reasonable vaults would be possible without CTV, b= +ut they<br>would be less efficient, particularly in the case of sending to = +many addresses<br>in a single unvaulting flow.<br><br>### Distilling OP_VAU= +LT<br><br>Abstracting from the implementation details, I mentally model a v= +ault as a<br>simple state machine with 2 states: [V] and [U]:<br><br>[V]: t= +he initial vault UTXO(s);<br>[U]: the utxo produced by the "trigger tr= +ansaction" during unvaulting.<br><br>On the typical path: one or more = +[V] UTXOs are sent to the [U] state, and after<br>a timelock set on [U] exp= +ires, [U] is spent to one or several destinations.<br>Crucially, the destin= +ation outputs and amounts are already decided when [V] is<br>spent into [U]= +.<br><br>At any time before the funds are spent from [U], they can always b= +e spent by<br>sending them to some specified recovery path.<br><br>There ar= +e two key elements that are part of OP_VAULT's semantics, and could be<= +br>generalized:<br><br>=E2=88=92 Forcing the script/amount of the next step= +on<br>=E2=88=92 Storing some data for future Script's access (in the va= +ult's case, a hash<br> that commits to the final withdrawal transacti= +on).<br><br>CICV/COCV generalize both to arbitrary scripts (taptrees) and s= +tate machines,<br>and to dynamical and witness-dependent data embedded in t= +he pubkey of a P2TR<br>output.<br><br>### Vault parameters<br><br>A contrac= +t that represents a vault has the following parameters (hardcoded in<br>the= + script when the vault is created):<br><br>- alternate_pk: a key that can b= +e used any time.<br>- spend_delay: the relative timelock before the withdra= +wal can be finalized;<br>- recover_pk: a pubkey for a P2TR output where fun= +ds can be sent at any time.<br><br>The alternate_pk is a pubkey that can op= +tionally be used as the key-path<br>spending condition for both states [V] = +and [U]. If such a spending condition is not<div>desired, it can be replace= +d with a NUMS point, making the key-path unspendable.<br><br>The spend_dela= +y is the number of blocks that must be mined before the final<br>withdrawal= + transaction<br><br>In this example we also use an unvault_pk needed to aut= +horize the unvaulting<br>process (that is, spend [V] into [U]); this could = +be replaced with any miniscript<br>or other conditions expressible in Scrip= +t.<br><br>### P2TR structure for [V] (vault)<br><br>internal key: alternate= +_pk<br><br>Script 1: "trigger"<br> # witness: <out_i>= +; <ctv-hash><br><font face=3D"monospace">{<br> <alternate_pk>= +;,<br> <merkle root of U's taptree>,<br> 2, OP_ROLL,<br> = + OP_CHECKOUTPUTCONTRACTVERIFY,<br><br> <unvault_pk><br> OP_CHEC= +KSIG<br>}</font><br><br>Script 2: "recover"<br> # witness:= + <out_i><br><font face=3D"monospace">{<br> recover_pk,<br> OP_0= +, # no data tweak<br> OP_0, = + # no taptweak<br> OP_CHECKOUTPUTCONTRACTVERIFY,<br> OP_TRUE<br>= +}</font><br><br>The "trigger" script requires in the witness an o= +utput index and the ctv-hash<br>that describes the withdrawal transaction.<= +br>COCV forces the output to contain the ctv-hash as embedded data.<br>That= +'s followed by the unvaulting condition =E2=88=92 in this example, a si= +mple<br>signature check.<br><br>The "recover" script doesn't = +require any signature, and it simply forces<br>the output specified in the = +witness to be a P2TR output with recover_pk as its<br>pubkey.<br><br>(Omitt= +ing the "recover" script in [V] would reduce the size of the witn= +ess by<br>32 bytes in the expected case, and might be preferred for some us= +ers)<br><br>### P2TR structure for [U] (unvaulting state)<br><br>internal k= +ey: alternate_pk (tweaked with ctv_hash)<br><br>Script 1: "withdrawal&= +quot;<br> # witness: <ctv_hash><br><font face=3D"monospace">{<= +br> OP_DUP,<br><br> # check that the top of the stack is the<br> #= + embedded data in the current input<br> <alternate_pk>, OP_SWAP,<b= +r> OP_CHECKINPUTCONTRACTVERIFY,<br><br> # Check timelock<br> <s= +pend_delay>,<br> OP_CHECKSEQUENCEVERIFY,<br> OP_DROP,<br><br> #= + Check that the transaction output is as expected<br> OP_CHECKTEMPLATEVE= +RIFY<br>}</font><br><br>Script 2: "recover"<br> # witness:= + <out_i><br><font face=3D"monospace">{<br> <recover_pk>,<br>= + OP_0,<br> OP_0,<br> OP_CHECKOUTPUTCONTRACTVERIFY,<br> OP_TRUE<= +br>}</font><br><br>The "withdrawal" finalizes the transaction, by= + checking that the timelock expired and</div><div>the outputs satisfy the C= +TV hash that was committed to in the previous transaction.<br><br>The "= +;recover" script is identical as before.<br><br><br>### Differences wi= +th OP_VAULT vaults<br><br>Here I refer to the latest version of OP_VAULT at= + the time of writing. [5]<br>It is not a thorough analysis.<br><br>Unlike t= +he implementation based on OP_VAULT, the [V] utxos don't have an option= +<br>to add an additional output that is sent back to the same exact vault.<= +br>Supporting this use case seems to require a more general way of handling= + the<br>distribution of amounts than what I discussed in the section above:= + that would<br>in fact need to be generalized to the case of multiple<br>OP= +_CHECKOUTPUTCONTRACTVERIFY opcodes executed for the same input.<br><br>By s= +eparating the ctv-hash (which is considered "data") from the scri= +pts in the<br>taptree, one entirely avoids the need to dynamically create t= +aptrees and<br>replace leaves in the covenant-encumbered UTXOs; in fact, th= +e taptrees of [V]<br>and [U] are already set in stone when [V] utxos are cr= +eated, and only the<br>"data" portion of [U]'s scriptPubKey i= +s dynamically computed. In my opinion,<br>this makes it substantially easie= +r to program "state machines" that control the<br>behavior of coi= +ns, of which vaults are a special case.<br><br>I hope you'll find this = +interesting, and look forward to your comments.</div><div><br></div><div>Sa= +lvatore Ingala<br><br><br>[1] - <a href=3D"https://lists.linuxfoundation.or= +g/pipermail/bitcoin-dev/2022-November/021223.html" rel=3D"noreferrer nofoll= +ow noopener" target=3D"_blank">https://lists.linuxfoundation.org/pipermail/= +bitcoin-dev/2022-November/021223.html</a><br>[2] - <a href=3D"https://githu= +b.com/bitcoin/bips/pull/1421" rel=3D"noreferrer nofollow noopener" target= +=3D"_blank">https://github.com/bitcoin/bips/pull/1421</a><br>[3] - <a href= +=3D"https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki" rel=3D"= +noreferrer nofollow noopener" target=3D"_blank">https://github.com/bitcoin/= +bips/blob/master/bip-0341.mediawiki</a><br>[4] - <a href=3D"https://lists.l= +inuxfoundation.org/pipermail/bitcoin-dev/2021-September/019420.html" rel=3D= +"noreferrer nofollow noopener" target=3D"_blank">https://lists.linuxfoundat= +ion.org/pipermail/bitcoin-dev/2021-September/019420.html</a><br>[5] - <a hr= +ef=3D"https://github.com/bitcoin/bips/blob/7112f308b356cdf0c51d917dbdc1b98e= +30621f80/bip-0345.mediawiki" rel=3D"noreferrer nofollow noopener" target=3D= +"_blank">https://github.com/bitcoin/bips/blob/7112f308b356cdf0c51d917dbdc1b= +98e30621f80/bip-0345.mediawiki</a><br></div></div></div> + + </blockquote><br> + </div></blockquote></div> + +--0000000000005abd3905fab19f16-- + + |