summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSalvatore Ingala <salvatore.ingala@gmail.com>2023-05-02 10:21:01 +0200
committerbitcoindev <bitcoindev@gnusha.org>2023-05-02 08:21:17 +0000
commit197449274e9351d9ad755d0a4c1e61fde7c0624a (patch)
treef0ab3997a980b50eccc0d2aacbb5e9ae41a048fa
parent3bbc4305ac326d4b2d9e98db23e6f7a54b66a9a4 (diff)
downloadpi-bitcoindev-197449274e9351d9ad755d0a4c1e61fde7c0624a.tar.gz
pi-bitcoindev-197449274e9351d9ad755d0a4c1e61fde7c0624a.zip
Re: [bitcoin-dev] Vaults in the MATT framework
-rw-r--r--29/3d7fd3d9a6937c19e2b31520dfdd6fa8346044992
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&#39;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>&quot;embed&quot; some data in the next output, and decide its script; =
+CICV<br>allows &quot;reading&quot; this data.<br>The design I proposed on t=
+aproot is surely not the only possible way,<br>but it&#39;s the most simple=
+/elegant I could come up with. Moreover, it<br>doesn&#39;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&#39;re checking that the script of an input/output<br>equals a certai=
+n value, which is not possible in today&#39;s Script.<br>I think that&#39;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 &quot;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 &quot;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&#39;=
+ 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 &lt;<a href=3D"mailto:michaelfolkson@protonmail.com">=
+michaelfolkson@protonmail.com</a>&gt; 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,&quot;Liberation Mono&quot;,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,&quot;Liberation Mono&quot;,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&quot;,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,&quot;Liberation Mono&quot;,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,&quot;Liberation Mono&quot;,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,&quot;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,&quot;Liberation Mon=
+o&quot;,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 &lt;<a href=3D"mailto:bitcoin-dev@lists.linuxfoundation.org" target=3D"=
+_blank">bitcoin-dev@lists.linuxfoundation.org</a>&gt; 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 &quot;completeness&quot; 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&#39;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&#39;s Script and<br>not the amounts; more on that below.<br=
+><br>Other than that, the semantics should be quite close to the &quot;righ=
+t&quot; 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() &lt; 2)<br> return set_error(serror, SCRIPT_ERR_INVAL=
+ID_STACK_OPERATION);<br> valtype&amp; x =3D stacktop(-2);<br> valtype=
+&amp; 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&lt;const unsigned char&gt;{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, &amp;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() &lt; 4)<br> return set_error(serror, SC=
+RIPT_ERR_INVALID_STACK_OPERATION);<br> int out_i =3D CScriptNum(stacktop=
+(-4), fRequireMinimal).getint();<br> valtype&amp; x =3D stacktop(-3);<br=
+> valtype&amp; taptree =3D stacktop(-2);<br> valtype&amp; 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 &amp;&amp; d.size() =
+!=3D 32))<br> return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPER=
+ATION);<br> if (out_i &lt; 0 || out_i &gt;=3D (int)outps-&gt;size())<br>=
+ return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);<br> =
+ const XOnlyPubKey nakedXOnlyKey{Span&lt;const unsigned char&gt;{x.data(),=
+ x.data() + 32}};<br> const uint256 data(d);<br> const uint256 *data_=
+ptr =3D (d.size() =3D=3D 0 ? nullptr : &amp;data);<br> const uint256 mer=
+kle_tree(taptree);<br> CScript scriptPubKey =3D outps-&gt;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=
+&lt;const unsigned char&gt;{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, &amp;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&#39;=
+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&#39=
+;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&#39;s script evaluation.<br><=
+br>This behaviour is adequate for vaults and likely suitable for many other=
+<br>applications; however, it&#39;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&#39;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&#3=
+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&#39;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 &quot;trigger tr=
+ansaction&quot; 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&#39;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&#39;s access (in the va=
+ult&#39;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: &quot;trigger&quot;<br> # witness: &lt;out_i&gt=
+; &lt;ctv-hash&gt;<br><font face=3D"monospace">{<br> &lt;alternate_pk&gt=
+;,<br> &lt;merkle root of U&#39;s taptree&gt;,<br> 2, OP_ROLL,<br> =
+ OP_CHECKOUTPUTCONTRACTVERIFY,<br><br> &lt;unvault_pk&gt;<br> OP_CHEC=
+KSIG<br>}</font><br><br>Script 2: &quot;recover&quot;<br> # witness:=
+ &lt;out_i&gt;<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 &quot;trigger&quot; 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=
+&#39;s followed by the unvaulting condition =E2=88=92 in this example, a si=
+mple<br>signature check.<br><br>The &quot;recover&quot; script doesn&#39;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 &quot;recover&quot; 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: &quot;withdrawal&=
+quot;<br> # witness: &lt;ctv_hash&gt;<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> &lt;alternate_pk&gt;, OP_SWAP,<b=
+r> OP_CHECKINPUTCONTRACTVERIFY,<br><br> # Check timelock<br> &lt;s=
+pend_delay&gt;,<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: &quot;recover&quot;<br> # witness:=
+ &lt;out_i&gt;<br><font face=3D"monospace">{<br> &lt;recover_pk&gt;,<br>=
+ OP_0,<br> OP_0,<br> OP_CHECKOUTPUTCONTRACTVERIFY,<br> OP_TRUE<=
+br>}</font><br><br>The &quot;withdrawal&quot; 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 &quot=
+;recover&quot; 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&#39;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 &quot;data&quot;) 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>&quot;data&quot; portion of [U]&#39;s scriptPubKey i=
+s dynamically computed. In my opinion,<br>this makes it substantially easie=
+r to program &quot;state machines&quot; that control the<br>behavior of coi=
+ns, of which vaults are a special case.<br><br>I hope you&#39;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--
+
+