From 58cbc4e9b1c73995b9972b06b46693a313b26dfa Mon Sep 17 00:00:00 2001 From: James O'Beirne Date: Tue, 21 Feb 2023 11:40:31 -0500 Subject: vaults: various feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks to Vojtěch Strnad for most of this. --- bip-vaults.mediawiki | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'bip-vaults.mediawiki') diff --git a/bip-vaults.mediawiki b/bip-vaults.mediawiki index c5738a0..fcd16c8 100644 --- a/bip-vaults.mediawiki +++ b/bip-vaults.mediawiki @@ -68,9 +68,9 @@ key winds up being ''too'' highly secure. Institutional custodians of Bitcoin would likely use vaults in similar fashion. -===== Avoiding the $5 wrench attack ===== +===== Provable timelocks ===== -This proposal uniquely provides a solution to the +This proposal provides a solution to the [https://web.archive.org/web/20230210123933/https://xkcd.com/538/ "$5 wrench attack."] By setting the spend delay to, say, a week, and using as the recovery path a script that enforces a longer relative timelock, the owner of the vault can @@ -122,8 +122,8 @@ Having a "general" covenant mechanism that can encode arbitrary transactional state machines would allow us to solve these issues, but at the cost of complex and large scripts that would probably be duplicated many times over in the blockchain. The particular design and deployment timeline of such a general -framework is also uncertain. There are no sample vault implementations using -these means known to the author. +framework is also uncertain. This approach was demonstrated +[https://blog.blockstream.com/en-covenants-in-elements-alpha/ in 2016]. This proposal intends to address the problems outlined above by providing a delay period/recovery path use with minimal transactional and @@ -135,7 +135,7 @@ The design goals of the proposal are: * '''batched operations''' for recovery and withdrawal to allow managing multiple vault coins efficiently. -* '''unbounded partial withdrawals''', which allows users to withdrawal partial vault balances without having to perform the setup ceremony for a new vault. +* '''unbounded partial withdrawals''', which allows users to withdraw partial vault balances without having to perform the setup ceremony for a new vault. * '''dynamic unvault targets''', which allow the proposed withdrawal target for a vault to be specified at withdrawal time rather than when the vault is first created. This would remove the need for a prespecified, intermediate wallet that only exists to route unvaulted funds to their desired destination. @@ -145,7 +145,7 @@ These goals are accompanied by basic safety considerations (e.g. not being vulnerable to pinning) and a desire for concision, both in terms of the number of outputs created as well as script sizes. -This proposal is designed to be compatible with any future sighash modes (e.g. SIGHASH_GROUP) or fee management strategies (e.g. [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-September/018168.html transaction sponsors]) that may be introduced. Use of these opcodes will benefit from, but do not strictly rely on, future transaction versions (e.g. [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-September/020937.html v3]) and [https://github.com/instagibbs/bips/blob/ephemeral_anchor/bip-ephemeralanchors.mediawik ephemeral anchors]. +This proposal is designed to be compatible with any future sighash modes (e.g. SIGHASH_GROUP) or fee management strategies (e.g. [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-September/018168.html transaction sponsors]) that may be introduced. Use of these opcodes will benefit from, but do not strictly rely on, [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-September/020937.html v3 transaction relay] and [https://github.com/instagibbs/bips/blob/ephemeral_anchor/bip-ephemeralanchors.mediawiki ephemeral anchors]. == Design == @@ -249,11 +249,9 @@ The tapscript opcodes OP_SUCCESS187 (0xbb) and ==== Witness program ==== When evaluating OP_VAULT (OP_SUCCESS187, -0xbb), the witness program is pushed onto the stack for the -following result (stack shown top to bottom): +0xbb), the expected format of the stack, shown top to bottom, is: -OP_VAULT (*) being evaluated @@ -262,7 +260,7 @@ OP_VAULT (*) being evaluated where * is a 32 byte tagged hash of the scriptPubKey used to authorize the spend of this output into an OP_UNVAULT trigger output -** tagged_hash("VaultTriggerSPK", spk), per BIP-0340. +** tagged_hash("VaultTriggerSPK", ), per BIP-0340. ** If this value is not 32 bytes, script execution when spending this output MUST fail and terminate immediately. ** Because this parameter's scriptPubKey is committed to using a hash, witness version upgradeability for the trigger key is preserved. @@ -301,12 +299,8 @@ where ==== OP_VAULT evaluation for recovery spend ==== -* If the recovery output does not have an nValue greater than this input's amount, the script MUST fail and terminate immediately. -* (Deferred) if the recovery output does not have an nValue equal to the sum of all OP_VAULT/OP_UNVAULT inputs with a corresponding recovery sPK hash, the transaction validation MUST fail.'''How do recovery transactions pay for fees?''' If the recovery is unauthorized, fees are attached either via CPFP with an ephemeral anchor or as inputs which are solely spent to fees (i.e. no change output). If the recovery is authorized, fees can be attached in any manner, e.g. unrelated inputs and outputs or CPFP via anchor. -** Note that in the draft implementation, this is facilitated by a "deferred check" which is queued by the script interpreter, but executed after the script interpreter has finished, in other validation code.'''Why does this proposal require a "deferred checks" framework for correct script evaluation?''' The deferred checks framework is an augmentation to execution of the Bitcoin script interpreter. Currently, the validity of each input is checked in an order-indepdendent manner across all inputs in a transaction. Because this proposal allows batching the spend of multiple vault inputs into a single recovery or withdrawal output, we need a mechanism to ensure that all expected values per output can be summed and then checked. This necessitates the introduction of an "aggregating" set of checks which can only be executed after each input's script is evaluated. Note that similar functionality would be required for batch input validation or cross-input signature aggregation. -* The script must FAIL (by policy, not consensus) and terminate immediately if neither'''Why are recovery transactions required to be replaceable?''' In the case of unauthorized recoveries, an attacker may attempt to pin recovery transactions by broadcasting a "rebundled" version with a low fee rate. Vault owners must be able to overcome this with replacement. In the case of authorized recovery, if an attacker steals the recovery authorization key, the attacker may try to pin the recovery transaction during theft. Requiring replaceability ensures that the owner can always raise the fee rate of the recovery transaction, even if they are RBF rule #3 griefed in the process. -*# the input is marked as opt-in replaceable by having an nSequence number less than 0xffffffff - 1, per [https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki BIP-0125], nor -*# the version of the recovery transaction has an nVersion equal to 3. +* If the recovery output does not have an nValue greater than or equal to this input's amount, the script MUST fail and terminate immediately. +* (Deferred'''What is a deferred check and why does this proposal require them for correct script evaluation?''' A deferred check is a validation check that is executed only after all input scripts have been validated, and is based on aggregate information collected during each input's EvalScript run.

Currently, the validity of each input is (usually) checked concurrently across all inputs in a transaction. Because this proposal allows batching the spend of multiple vault inputs into a single recovery or withdrawal output, we need a mechanism to ensure that all expected values per output can be summed and then checked. This necessitates the introduction of an "aggregating" set of checks which can only be executed after each input's script is evaluated. Note that similar functionality would be required for batch input validation or cross-input signature aggregation.
) if the recovery output does not have an nValue equal to the sum of all OP_VAULT/OP_UNVAULT inputs with a corresponding recovery sPK hash, the transaction validation MUST fail.'''How do recovery transactions pay for fees?''' If the recovery is unauthorized, fees are attached either via CPFP with an ephemeral anchor or as inputs which are solely spent to fees (i.e. no change output). If the recovery is authorized, fees can be attached in any manner, e.g. unrelated inputs and outputs or CPFP via anchor. The stack may now have 0 or more elements. Any items on the stack will be used to verify the recovery authorization witness program, if any. @@ -378,9 +372,10 @@ spent. Its presence is optional. For each vault input citing a particular , the output located at vout[] (the "trigger output") must: -* have as its scriptPubKey a witness program version 1 with a single OP_UNVAULT tapscript, having the internal key lift_x(0x0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0), per the NUMS point mentioned in [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#user-content-Design BIP-0341].'''Why must the OP_UNVAULT taproot use a NUMS point as its internal key?''' This ensures that an OP_UNVAULT trigger output is verifiable as expected. It also ensures that it is spendable only by the conditions of the vault. +* have as its scriptPubKey a witness program with a single OP_UNVAULT tapscript, having the internal x-only key 0x0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0, per the NUMS point mentioned in [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#constructing-and-spending-taproot-outputs BIP-0341].'''Why must the OP_UNVAULT taproot use a predefined NUMS point as its internal key?''' This ensures that an OP_UNVAULT trigger output is verifiable as expected. It also ensures that it is spendable only by the conditions of the vault. ** If the witness program has a version less than 1, the script MUST fail and terminate immediately. -** If the scriptPubKey of the output does not match the expected scriptPubKey, as computed by creating a taproot output using the cited NUMS point and a single tapscript spend condition of the form
OP_UNVAULT,
the script MUST fail and terminate immediately. +** If the witness program has a version greater than 1, the script MUST succeed to enable upgradeability. +** If the witness program has a version of 1 and the scriptPubKey of the output does not match the expected scriptPubKey, as computed by creating a taproot output using the cited NUMS point and a single tapscript spend condition of the form
OP_UNVAULT,
the script MUST fail and terminate immediately. ** Witness versions greater than 1 are allowed for upgradeability. * If there does not exist a revault output in the transaction for this input: @@ -486,6 +481,13 @@ def serialize_txout(txo: CTxOut) -> bytes: If the above conditions do not fail, a single true value (0x01) is pushed to the stack. +== Policy changes == + +In order to prevent possible pinning attacks, recovery transactions must be replaceable. + +* When validating an OP_VAULT/OP_UNVAULT input being spent towards a recovery, the script must FAIL (by policy, not consensus) and terminate immediately if neither'''Why are recovery transactions required to be replaceable?''' In the case of unauthorized recoveries, an attacker may attempt to pin recovery transactions by broadcasting a "rebundled" version with a low fee rate. Vault owners must be able to overcome this with replacement. In the case of authorized recovery, if an attacker steals the recovery authorization key, the attacker may try to pin the recovery transaction during theft. Requiring replaceability ensures that the owner can always raise the fee rate of the recovery transaction, even if they are RBF rule #3 griefed in the process. +*# the input is marked as opt-in replaceable by having an nSequence number less than 0xffffffff - 1, per [https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki BIP-0125], nor +*# the version of the recovery transaction has an nVersion equal to 3. == Implementation == -- cgit v1.2.3