Subject: Re: [bitcoin-dev] OP_VAULT: a new vault proposal

From: "James O'Beirne" <[email-masked]>
Date: Tue, 10 Jan 2023 08:35:04 -0500

Greg explained his suggestion to me off-list, and I think it's a good one.
To summarize, consider the normal "output flow" of an expected vault use:

(i) output to be vaulted
  => (ii) OP_VAULT output
    => (iii) OP_UNVAULT "trigger" output
      => (iv) final output

In my existing draft implementation, all outputs aside from (iii), the
OP_UNVAULT trigger, can be P2TR or P2WSH. In other words, those outputs can
hide their true script until spend. In my draft, the OP_UNVAULT trigger had
to be bare so that the script interpreter could inspect part of it for
validity: "does this OP_UNVAULT have the same <recovery-spk-hash> and
<spend-delay> as the OP_VAULT?"

If that output wasn't bare, because the <target-hash> is variable at the
time of OP_UNVAULT output creation, the script interpreter would have no
way of constructing the expected scriptPubKey.

Greg's suggestion would allow that output to be any kind of script. He
suggests to put the <target-hash> onto the witness stack when spending the
OP_VAULT output (and creating the OP_UNVAULT output). If we did that, the
script interpreter could e.g. use a NUMS point (i.e. a publicly known point
with no usable private key) to construct a Taproot configuration that looks
like

  tr(NUMS, {<OP_UNVAULT <recovery-key> <spend-delay> <target-hash>})

and check if the scriptPubKey of the proposed OP_UNVAULT output matches
that. This would allow all outputs in vault lifecycles to be P2TR, for
example, which would conceal the operation of the vault - a very nice
feature!

This would also allow the OP_VAULT/OP_UNVAULT opcodes to be implemented as
Taproot-only OP_SUCCESSx opcodes, if that was decided to be preferable.

The problem is how to (and whether to) enable something similar for witness
v0 outputs. For example, if we want the (ii) and (iii) output scripts to
live behind P2WSH. One (kind of hacky) option to enable this is to have the
script interpreter construct the expected OP_UNVAULT scriptPubKey on the
basis of what witness version it sees. For example, if it sees "OP_0 <32
bytes data>", it would use <target-hash> on the witness stack to construct
a fitting P2WSH scriptPubKey that is compatible with the OP_VAULT being
spent, and then match against that. But if it detects "OP_1 <32 bytes
data>", it would do the same process for an expected Taproot-with-NUMS
output.

---

Anyway, sorry if that was more verbose than necessary, but I think it's a
really great suggestion from Greg. I'll look at modifying the
implementation accordingly. I'd be curious to hear what others think as
well.