public inbox for bitcoindev@googlegroups.com
 help / color / mirror / Atom feed
From: Greg Sanders <gsanders87@gmail•com>
To: Anthony Towns <aj@erisian•com.au>
Cc: Bitcoin Protocol Discussion <bitcoin-dev@lists•linuxfoundation.org>
Subject: Re: [bitcoin-dev] BIP for OP_VAULT
Date: Thu, 9 Mar 2023 13:45:15 -0500	[thread overview]
Message-ID: <CAB3F3Dt_0JB1W-JEEFs5j3HHNGfmXd9uU6civ7Ue8go=+z79Eg@mail.gmail.com> (raw)
In-Reply-To: <ZAcx7oEZxC9BiWvg@erisian.com.au>

[-- Attachment #1: Type: text/plain, Size: 7991 bytes --]

AJ,

Interesting stuff! Just a couple thoughts on these proposed opcodes, at
least one we discussed elsewhere:

1) OP_FORWARD_SELF is a JET of OP_FLU in the revaulting common case. Maybe
obvious but I missed this initially and thought it was useful to be pointed
out.

2)  Using these extended primitives, you can do rate-limiting of the two
step unvaulting, or just a single step vault by committing to the partial
values. For the single stage case it's something like:

$recovery = Same As Before

$withdrawal = <deposit-delay> OP_CSV OP_DROP <pubkey> OP_CHECKSIG OP_DUP
<V> OP_LESSTHANOREQUAL OP_VERIFY OP_FORWARD_PARTIAL OP_FORWARD_TARGET
OP_FORWARD_SELF

$withdrawal is spent by:

<self-idx> <target-idx> <spk> <0<=v<=V> <signature>

where "V"  is the max allowed withdrawal value, and "deposit-delay" the
required gap in withdrawals

Due to the OP_LEQ, you are bound to ~21 BTC in value for this operation,
but for larger vaults it's pretty trivial to add larder fixed denominations
to "peel out" value until you get to your final ~21 BTC.

This rate-limiting(in either the two-stage or one-stage scheme) can limit
the risk of theft during a watchtower outage to a constant value per utxo
per time period of watchtower failure. As we've seen in the past with LN
infrastructure, software risks are often correlated, so it's a good idea to
build in belt and suspenders where we can or at least have them available
when possible.

Cheers,
Greg


On Tue, Mar 7, 2023 at 7:45 AM Anthony Towns <aj@erisian•com.au> wrote:

> On Mon, Mar 06, 2023 at 10:25:38AM -0500, James O'Beirne via bitcoin-dev
> wrote:
> > What Greg is proposing above is to in essence TLUV-ify this proposal.
>
> FWIW, the way I'm thinking about this is that the "OP_VAULT" concept is
> introducing two things:
>
>  a) the concept of "forwarding" the input amount to specified
>     outputs in a way that elegantly allows merging/splitting
>
>  b) various restrictions on the form of the output scripts
>
> These concepts go together well, because restricting an output script is
> only an interesting thing to do if you're moving value from this input
> into it. And then it's just a matter of figuring out a nice way to pick
> opcodes that combine those two concepts in interesting ways.
>
> This is different from TLUV, in that TLUV only did part (b), and
> assumed you'd do part (a) manually somehow, eg via "OP_IN_OUT_AMOUNT"
> and arithmetic opcodes. The advantage of this new approach over that
> one is that it makes it really easy to get the logic right (I often
> forgot to include the IN_OUT_AMOUNT checks at all, for instance), and
> also makes spending multiple inputs to a single output really simple,
> something that would otherwise require kind-of gnarly logic.
>
> I think there are perhaps four opcodes that are interesting in this class:
>
>    idx sPK OP_FORWARD_TARGET
>      -- sends the value to a particular output (given by idx), and
>         requires that output have a particular scriptPubKey (given
>         by sPK).
>
>    idx [...] n script OP_FORWARD_LEAF_UPDATE
>      -- sends the value to a particular output (given by idx), and
>         requires that output to have almost the same scriptPubKey as this
>         input, _except_ that the current leaf is replaced by "script",
>         with that script prefixed by "n" pushes (of values given by [...])
>
>    idx OP_FORWARD_SELF
>      -- sends the value to a particular output (given by idx), and
>         requires that output to have the same scriptPubKey as this input
>
>    amt OP_FORWARD_PARTIAL
>      -- modifies the next OP_FORWARD_* opcode to only affect "amt",
>         rather than the entire balance. opcodes after that affect the
>         remaining balance, after "amt" has been subtracted. if "amt" is
>         0, the next OP_FORWARD_* becomes a no-op.
>
> Then each time you see OP_FORWARD_TARGET or OP_FORWARD_LEAF_UPDATE, you
> accumulate the value that's expected to be forwarded to the output by
> each input, and verify that the amount for that output is greater-or-equal
> to the accumulated value.
>
> > ## Required opcodes
> > - OP_VAULT: spent to trigger withdrawal
> > - OP_VAULT_RECOVER: spent to recover
>
> Naming here is OP_VAULT ~= OP_FORWARD_LEAF_UPDATE; OP_VAULT_RECOVER ~=
> OP_FORWARD_TARGET.
>
> > For each vault, vaulted coins are spent to an output with the taproot
> > structure
> >
> >   taproot(internal_key, {$recovery_leaf, $trigger_leaf, ...})
> >
> > where
> >
> >   $trigger_leaf =
> >     <trigger> <auth> <script> <spend-delay> OP_VAULT
>
> With the opcodes above, the trigger_leaf (for spending some of the
> vaulted funds via your hot wallet) script might look like:
>
>    OP_FORWARD_PARTIAL OP_FORWARD_SELF
>    1 "288 OP_CSV OP_DROP OP_CTV" OP_FORWARD_LEAF_UPDATE
>    key CHECKSIG
>
> So if you have 2.0 BTC in a vault utxo, you might spend 0.4 BTC by
> supplying the witness data:
>
>   160000000  (1.6BTC in sats)
>   0 (output 0 puts 1.6BTC goes back into the vault)
>   <ctvhash> (the outputs where you want the remaining 0.4 BTC to end up)
>   1 (the output idx that will be spend via the CTV path once the CSV
>      delay is done)
>   <sig> (a signature of this transaction via the hot wallet "key")
>
> That is, the script becomes:
>
>   160000000 FORWARD_PARTIAL
>   0 FORWARD_SELF
>   1 <ctvhash> 1 "288 CSV DROP CTV" FORWARD_LEAF_UPDATE
>   sig key CHECKSIG
>
> Output 1 would then have a tapscript of "<ctvhash> 288 OP_CSV OP_DROP
> OP_CTV", satisfied with an empty witness stack (along with the recovery
> path, etc).
>
> Output 0 is just 1.6BTC back in your vault, and immediately available
> for use.
>
> Other inputs/outputs (for fees etc) would still be committed to by <sig>,
> so nothing here is malleable. The script here is about 45 bytes (compared
> to 34 for a simple "key CHECKSIG") and the witness data is about 105 bytes
> (compared to 65 bytes for just a signature), which seems pretty nice.
>
> >   ... =
> >     other (optional) leaves in the taptree
>
> This would allow you to have multiple hot wallets (if any of them are
> compromised you can still use the recovery path to avoid loss of funds;
> but if some hot wallet becomes temporarily *inaccessible* you can still
> easily spend the funds via one of the alternative hot wallets), or,
> if you have multiple watchtowers validating your spends and recovering
> funds to your cold wallet on a violation, you could have multiple recovery
> paths to provide some auditability for who triggered the recovery.
>
> > Happens via script-path spend to $expr_withdraw, i.e. a timelocked
> > OP_CTV.
>
> Note that if you calculated the OP_CTV incorrectly (eg, you don't set a
> correct nSequence timelock, so that any tx that passes OP_CTV won't pass
> the OP_CSV check, and vice-versa) then this spend path becomes invalid,
> and the funds can only be reclaimed via some other path (key path spend,
> recovery tapscript, potentially an alternative hotwallet script path).
>
> OP_FORWARD_LEAF_UPDATE is equivalent to a very specific form of TLUV,
> namely "FALSE <h> 2 TLUV", where "<h>" is calculated by building the
> script, prefixing the pushes, then doing the Hash_TapLeaf calculation.
>
> Not being able to tweak the internal public key ("FALSE" rather than
> "<x>") means this can't be used to build a coinpool with unilateral
> exit -- you can't remove your key from the key path, which screws over
> everyone who's still in the coinpool.
>
> On the other hand, not tweaking the internal public key avoids introducing
> all the x-only pubkey complications, and keeps it relatively simple,
> which is nice, and keeping things simple and targeted now means there's
> still plenty of OP_SUCCESS opcodes available later for something more
> general, if that turns out to be desirable.
>
> Cheers,
> aj
>

[-- Attachment #2: Type: text/html, Size: 9341 bytes --]

  reply	other threads:[~2023-03-09 18:45 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-02-13 21:09 James O'Beirne
2023-03-01 15:05 ` Greg Sanders
2023-03-02  4:46   ` Anthony Towns
2023-03-02 14:54     ` Greg Sanders
2023-03-02 19:51       ` Andrew Melnychuk Oseen
2023-03-06 15:25       ` James O'Beirne
2023-03-06 16:07         ` Greg Sanders
2023-03-07 12:45         ` Anthony Towns
2023-03-09 18:45           ` Greg Sanders [this message]
2023-03-10  1:08             ` Anthony Towns
2023-03-24 12:10           ` Anthony Towns
2023-03-29  7:10             ` Zac Greenwood
2023-03-29 19:57               ` alicexbt
2023-03-30  0:16                 ` Steve Lee
2023-03-30 10:39                 ` Zac Greenwood
2023-03-30 18:12                   ` alicexbt
2023-03-13 19:03       ` Brandon Black
2023-03-14 14:40         ` Greg Sanders
2023-03-11 20:53 ` Luke Dashjr
2023-03-13 14:55   ` Greg Sanders
2023-03-13 14:56     ` Greg Sanders
2023-03-13 20:55       ` Luke Dashjr
2023-03-16 14:44         ` Greg Sanders

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAB3F3Dt_0JB1W-JEEFs5j3HHNGfmXd9uU6civ7Ue8go=+z79Eg@mail.gmail.com' \
    --to=gsanders87@gmail$(echo .)com \
    --cc=aj@erisian$(echo .)com.au \
    --cc=bitcoin-dev@lists$(echo .)linuxfoundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox