<oembed><type>rich</type><version>1.0</version><author_name>npub1vtwuk4rjyj6zrq3tv2z9lvdm6a7g8zujf0gz9q2vljlztdaqw36sjjsjpg</author_name><author_url>https://nostr.ae/npub1vtwuk4rjyj6zrq3tv2z9lvdm6a7g8zujf0gz9q2vljlztdaqw36sjjsjpg</author_url><provider_name>njump</provider_name><provider_url>https://nostr.ae</provider_url><html>📅 Original date posted:2019-08-07&#xA;📝 Original message:Hi,&#xA;&#xA;I have a proposal for implementing bitcoin vaults in a way that does not&#xA;require any soft-forks or other software upgrades, although it could benefit&#xA;from SIGHASH_NOINPUT which I&#39;ll describe later.&#xA;&#xA;I call them pre-signed vaults.&#xA;&#xA;Vault definition&#xA;================&#xA;&#xA;Here, a vault is defined as a transaction setup scheme that binds both the user&#xA;and the attacker to always using a public observation and delay period before a&#xA;weakly-secured hot key is allowed to arbitrarily spend coins. This is the same&#xA;definition previously used[1]. During the delay period, there is an opportunity&#xA;to initiate recovery/clawback which can either trigger deeper cold storage&#xA;parameters or at least reset the delay period to start over again for the same&#xA;keys.&#xA;&#xA;One of the important components of this is the delete-the-key pre-signed&#xA;transaction concept, where only a single transaction is (pre)signed before&#xA;deleting the key. This is basically an emulation of a covenant and enforces a&#xA;certain outcome.&#xA;&#xA;Background and motivation&#xA;=========================&#xA;&#xA;I was looking at Eyal and Sirer&#39;s 2016 vaults paper [1], and I saw this&#xA;headscratcher:&#xA;&#xA;&gt; Vault transactions use a delay mechanism. We note that vault transactions&#xA;&gt; cannot be implemented with existing timing mechanisms such as&#xA;&gt; CHECKLOCKTIMEVERIFY opcode or transaction locktime.&#xA;&#xA;This was probably written before the introduction of OP_CHECKSEQUENCEVERIFY.&#xA;Still, a viable construction would have more steps than just using OP_CSV. They&#xA;were probably not thinking about what those steps might be, because in the&#xA;context of the paper they were proposing a bitcoin vault implemented using&#xA;recursive consensus-enforced covenants via a new opcode, which obviously cannot&#xA;be deployed without an upgrade fork. Covenants have been discussed for years,&#xA;but require new opcodes or other consensus-enforcement changes.&#xA;&#xA;Relative locktimes are useful here because there is no knowledge as to when the&#xA;transactions might be broadcasted in the future. The delays need to be relative&#xA;to after the transaction is included in the blockchain, not to setup&#xA;initialization time.&#xA;&#xA;Also, from [2]:&#xA;&#xA;&gt; We show that a [vault transaction] mechanism is currently not possible in all&#xA;&gt; cryptocurrencies [...] Bitcoin&#39;s scripting language requires support for&#xA;&gt; covenants.&#xA;&#xA;I haven&#39;t seen any previous proposal for how to implement recursive bitcoin&#xA;vaults without a fork and without a covenant. After asking around, I am pretty&#xA;sure this is somewhat novel. The closest I guess is [3].&#xA;&#xA;Vaults are particularly interesting as a bitcoin cold storage security&#xA;mechanism because they enable a publicly observable delay period during which&#xA;time a user could be alerted by a watchtower that a thief might be in the&#xA;process of stealing their coins, and then the user may take some actions to&#xA;place the coins back into the vault before the relative timelock expires. There&#xA;seems to be no way to get this notification or observation period without a&#xA;vault construction. It might have been assumed it required a covenant.&#xA;&#xA;Having a vault construction might go a long way to discourage would-be&#xA;attackers, on principle that the attacker might be incapable of recovering&#xA;their cost-of-attack because the recovery mechanism can lock up the coins&#xA;indefinitely. Griefing or denial-of-service would still be possible, of course,&#xA;but with multisig there might be some ways to put a halt to that as well. I am&#xA;working under the assumption that the attacker knows that the user is a vault&#xA;user.&#xA;&#xA;Vaults&#xA;======&#xA;&#xA;The idea is to have a sequence of pre-generated pre-signed transactions that&#xA;are generated in a certain way. The basic components are a vaulting transaction&#xA;that locks coins into a vault, a delayed-spend transaction which is the only&#xA;way to spend from a vault, and a re-vaulting transaction which can&#xA;recover/clawback coins from the delayed-spend transaction. The security of this&#xA;scheme is enforced by pre-signing transactions and deleting private keys, or&#xA;with the help of SIGHASH_NOINPUT then there&#39;s another scheme where private keys&#xA;are provably never known. This enforces that there&#39;s only a specific set of&#xA;possible outcomes at every step of the vault.&#xA;&#xA;Some examples of what the set of broadcasted transactions might look like in&#xA;regular usage:&#xA;&#xA;    coins -&gt; VT -&gt; DST -&gt; exit via hot wallet key&#xA;    coins -&gt; VT -&gt; DST -&gt; RVT&#xA;    coins -&gt; VT -&gt; DST -&gt; RVT -&gt; DST -&gt; ...&#xA;    coins -&gt; VT -&gt; ... -&gt; RVT998 -&gt; nuclear abort&#xA;&#xA;where:&#xA;    VT = vault transaction&#xA;    DST = delayed-spend transaction&#xA;    RVT = re-vaulting transaction&#xA;&#xA;The delayed-spending transaction would have a single output with a script like:&#xA;(&#xA;    30 days AND hot wallet key&#xA; OR 10 days AND re-vaulting public key&#xA; OR 1 day AND 4-of-7 multisig&#xA; OR 0 days and super-secure nuclear abort ragequit key&#xA;)&#xA;&#xA;Another diagram:&#xA;&#xA;    VT_100 -&gt; DST -&gt; (optionally) RVT -&gt; coins are now in VT_99&#xA;    VT_99 -&gt; DST -&gt; (optionally) RVT -&gt; coins are now in VT_98&#xA;    ...&#xA;    VT_1 -&gt; burn-all-coins nuclear abort ragequit (final)&#xA;&#xA;Definitions&#xA;===========&#xA;&#xA;Transactions and components:&#xA;&#xA;* Commitment/funding vault setup transaction. Signed after setting up the&#xA;transaction tree, and it is broadcasted whenever funds are to be placed into&#xA;the vault.&#xA;&#xA;* Delayed-spend transaction. Signed during the vault transaction tree setup,&#xA;and it is broadcasted when the user wants to withdraw coins from cold storage&#xA;or otherwise manipulate the coins. The output script template used by the&#xA;delayed-spend transaction was defined earlier.&#xA;&#xA;* Hot wallet key: Somewhat insecure key. This can also be multisig using&#xA;multiple hot keys.&#xA;&#xA;* Re-vaulting key: It is important to note that the private key either never&#xA;existed (SIGHASH_NOINPUT + P2WPK for the re-vaulting transaction) or the&#xA;private key was deleted after pre-signing the re-vaulting transaction.&#xA;&#xA;* 4-of-7 multisig: This is a group of differently-motivated individuals who are&#xA;responsible for signing transactions. This multisig group is not necessry to&#xA;describe the technique, I just think it&#39;s a useful feature for a vault to&#xA;include.&#xA;&#xA;* Nuclear abort key: Also unnecessary. This is a key for which only a single&#xA;signed transaction will ever exist, and that single transaction will spend to a&#xA;proof-of-burn key like 0x00. This key must be extremely secure, and if there&#xA;is any doubt about the ability to keep such a key secured, then it is better to&#xA;not include this in the protocol. Alternatively, maybe include it as an option&#xA;50 layers down in the revaulting sequence.&#xA;&#xA;* Nuclear-abort pre-signed transaction. This is signed during transaction tree&#xA;setup, before constructing the delayed-spend transaction. It is broadcasted&#xA;only if the user wants to provably relinquish coins forever without giving the&#xA;attacker any coins.&#xA;&#xA;* Re-vaulting transaction. This is where the magic happens. The re-vaulting&#xA;transaction is signed during transaction tree setup, before constructing the&#xA;delayed-spend transaction for the parent vault. The re-vaulting transaction is&#xA;broadcasted when someone wants to prevent a coin withdrawal during the public&#xA;observation delay period. The re-vaulting transaction spends the delayed-spend&#xA;transaction outputs. It has a single output with a script created by running&#xA;the entire vault setup function again. Hence, when the re-vaulting transaction&#xA;is confirmed, all of the coins go back into a new identically-configured vault&#xA;instead of being relinquished through the delayed-spend transaction timeout for&#xA;hot wallet key signing.&#xA;&#xA;* Special case: final transaction. This is the very first pre-signed&#xA;transaction during setup, and the transaction spends the coins using any&#xA;provable burn technique. This is broadcasted only at the end of the game, as an&#xA;ultimate abort and forfeiture of coins without giving in to an adversary. It&#39;s&#xA;similar to the nuclear-abort ragequit transaction but it sits at the same place&#xA;that a delayed-spend transaction would, at the very end of the rainbow or&#xA;yellow brick road.&#xA;&#xA;Example log during vault setup&#xA;==============================&#xA;&#xA;When running the recursive vault setup function, the created artifacts (in&#xA;order) will look like:&#xA;&#xA;1) choose one of:&#xA;   (first iteration) pre-signed burn-all-coins nuclear abort ragequit (final)&#xA;   (all others) a new vault setup transaction spendable only by its&#xA;                delayed-spend transaction&#xA;&#xA;2) pre-signed re-vaulting transaction sending to vault setup or final&#xA;transaction, with a unique private key&#xA;&#xA;3) pre-signed delayed-spend transaction, with a unique private key&#xA;&#xA;4) vault transaction spendable only by the delayed-spend public key&#xA;&#xA;Pseudocode&#xA;==========&#xA;&#xA;In pseudocode (where PTX is a pre-signed transaction function with&#xA;private key deletion):&#xA;&#xA;    VT(counter, *args, **kwargs) =&#xA;        if counter == 0:&#xA;            DST = PTX(&#34;burn-all-coins&#34;)&#xA;        else:&#xA;            next_vault = VT(counter-1, *args, **kwargs)&#xA;            revaulting = PTX(&#34;only spendable by next_vault public key&#34;)&#xA;            DST = PTX(&#34;DST policy including revaulting and other conditions&#34;)&#xA;        vault = PTX(&#34;spendable only by this DST&#34;)&#xA;        return vault&#xA;&#xA;Pre-signed transactions&#xA;=======================&#xA;&#xA;What has been known for a while is that a covenant can be somewhat emulated&#xA;using a pre-signed transaction where the user then deletes the private key,&#xA;enforcing that the user&#39;s chosen policy must be enforced since there is only&#xA;one existing option and there will only ever be one option.&#xA;&#xA;Such a scheme has been previously described for simple one-time and chained&#xA;vaults [3]. I have learned that the author has an implementation that is in&#xA;preparation, for a non-recursive version.&#xA;&#xA;Note that a series of pre-signed transactions can be considered to be an&#xA;emulation of a covenant. Imagine a linear chain of pre-signed transactions&#xA;where each hop has a relative locktime before being able to broadcast the next&#xA;transaction. To recover the coins at the end of the rainbow, one would need to&#xA;broadcast each sequential transaction in order and wait for the relative&#xA;timelocks to expire each time. Here, covenants provide something like an undo&#xA;for bitcoin, but only between pre-determined addresses and scripts.&#xA;&#xA;Fees for pre-signed transactions&#xA;================================&#xA;&#xA;There&#39;s a few different techniques to talk about:&#xA;&#xA;1) SIGHASH_SINGLE|SIGHASH_ANYONECANPAY to let someone add inputs and outputs.&#xA;This can get pretty complex though.&#xA;&#xA;2) Add a zero-value OP_TRUE output and let anyone spend the zero-value output&#xA;and attach a child-pays-for-parent (CPFP) transaction to pay for everything.&#xA;&#xA;3) Pre-sign a variety of different possible fee rates. Unfortunately this&#xA;involves an explosive blow-up in the amount of transaction data to generate. It&#xA;might actually be a reasonable blow-up amount, only resulting in a few hundred&#xA;megabytes of additional data. But given the other options, this is unnecessary.&#xA;&#xA;Delete the key (for pre-signed transactions)&#xA;============================================&#xA;&#xA;The delete-the-key trick is simple. The idea is to pre-sign at least one&#xA;transaction and then delete the private key, thus locking in that course of&#xA;action.&#xA;&#xA;Unfortunately, delete-the-key doesn&#39;t really work for multisig scenarios&#xA;because nobody would trust that anyone else in the scheme has actually deleted&#xA;the secret. If they haven&#39;t deleted the secret, then they have full unilateral&#xA;control to sign anything in that branch of the transaction tree. The only time&#xA;that delete-the-key might be appropriate would be where the user who deletes&#xA;the key and controls the key during the setup process is also the sole&#xA;beneficiary of the entire setup with the multisig participants.&#xA;&#xA;Alternative fee rates are easier to deal with using delete-the-key, compared to&#xA;a technique where the private key never existed which can only be used to sign&#xA;one fee rate per public key, requiring an entirely new vault subtree for each&#xA;alternative fee rate. With delete-the-key, the alternative fee rates are signed&#xA;with the private key before the private key is deleted.&#xA;&#xA;Multisig gated by ECDSA pubkey recovery for provably-unknown keys&#xA;=================================================================&#xA;&#xA;A group can participate in a multisig scheme with provably-unknown ECDSA keys.&#xA;Instead of deleting the key, the idea is to agree on a blockheight and then&#xA;select the blockhash (or some function of the chosen blockhash like&#xA;H(H(H(blockhash)))) as the signature. Next, the group agrees on a transaction&#xA;and they recover the public key from the signature using ECDSA pubkey recovery.&#xA;A pre-signed transaction is created, which will trigger the start of the public&#xA;observation period described earlier and also start the clock for the bip112&#xA;relative timelock on its output. In the output script, an OR branch&#xA;is added that enables the use of a re-vaulting key which could also be its own&#xA;separate multisig construction.&#xA;&#xA;This is incompatible with P2WPKH because the P2WPKH spending scriptSig needs to&#xA;have the pubkey (to check the hash of the pubkey against the pubkeyhash in the&#xA;scriptPubKey), which in turn makes it incompatible with ECDSA pubkey recovery&#xA;which requires a hash of the message. However, with P2WPK and SIGHASH_NOINPUT&#xA;instead of P2WPKH it could conceivably work. SIGHASH_NOINPUT is required because&#xA;otherwise the input includes a txid which references the public key. With P2WPK,&#xA;the scriptSig only needs a signature and not a public key. Note that what would&#xA;be required is a version of SIGHASH_NOINPUT that does not commit to the public&#xA;key, and I think a few of the NOINPUT proposals are committing to the public&#xA;key.&#xA;&#xA;Alternatively, there may be some constructions using the 2-party ECDSA&#xA;techniques or m-n party ECDSA techniques.&#xA;&#xA;Deploying exceedingly large scripts&#xA;===================================&#xA;&#xA;A brief interlude to share a somewhat obvious construction. I haven&#39;t seen this&#xA;written down yet.&#xA;&#xA;Suppose there is a bitcoin script that someone is interested in using, but it&#xA;far exceeds the size limits and sigop limits. To fix this, they would split up&#xA;the script into usable chunks, and then use the delete-the-key mechanism (or&#xA;the other one) to create an OR branch that is signable by a single key for&#xA;which only a single signature is known. That new pre-signed transaction would&#xA;spend to a script that has the output with the remainder of the script of&#xA;interest. Re-vaulting or clawback clauses can be added to that output as well,&#xA;but spending back to the original root script will only work by generating new&#xA;scripts and keys (since the final hash isn&#39;t known until the whole tree is&#xA;constructed, it&#39;s a dependency loop).&#xA;&#xA;Recursively-enforced multi-party multisig bitcoin vaults&#xA;========================================================&#xA;&#xA;Ideally, to enforce a covenant with impossible fairy dust magic, we would ask&#xA;for a bitcoin transaction that could be self-referential because the&#xA;only-one-signature-ever trick requires that the signed message be known before&#xA;producing the signature, and the signature has to be known before the public&#xA;key can be known, and the public key would have to be included in the&#xA;self-referential message/transaction hash value. So, that&#39;s a dependency loop&#xA;and it doesn&#39;t work. It would be interesting to explore a variation of this&#xA;idea with masking, such that a value X can be replaced by a hash over the whole&#xA;script with the X value, even though the real script will have the hash.&#xA;Someone else can figure that one out for me :-).&#xA;&#xA;Instead of the self-referential values attempting to reference the same&#xA;script that is in the process of being constructed, an alternative is to use&#xA;the same script template but populate it with different parameters. The script&#xA;template gets reused over and over again, all the way down the tree, until the&#xA;final transaction which could be &gt;100 years into the future once done adding up&#xA;all the relative locktimes. In fact, to create and populate this terrifying&#xA;recursive script tree, the final transaction needs to be created first, and&#xA;then it is given as input to the script template function and that output is&#xA;then given to the script template function itself-- and so on. At each stage,&#xA;there are additional pre-signed transactions and values to remember.&#xA;&#xA;This can be written as:&#xA;&#xA;    final_transaction = TX(spend to 0x0000 to burn the coins)&#xA;    initial_transaction = F(F(...F(final_transaction))&#xA;&#xA;    (This is missing parameters to indicate to the function what the spending&#xA;    keys requirements are to be.)&#xA;&#xA;See earlier explanation for more details.&#xA;&#xA;Each call to the template populating function produces values that each must be&#xA;preserved for a very long time. It is less safe to store all of the pre-signed&#xA;transactions together at the same time, but more convenient. With less&#xA;redundancy, there is an increased chance of losing data over time, which could&#xA;render the coins completely frozen. This doesn&#39;t particularly worry me because&#xA;forgetting a key has that property already, and this could be likened to&#xA;hundreds of megabytes of extra key data or something. Unlike the much smaller&#xA;covenant-based (opcode-based covenant) vault construction, the multiple layers&#xA;here can be separately stored and protected, which might be able to protect&#xA;against an adversary that has stolen some of the re-vaulting keys but not all&#xA;of them.&#xA;&#xA;Optimizations can be made to store parameters for generating the remainder of&#xA;the tree, such as using deterministic key derivation, such that megabytes of&#xA;data wouldn&#39;t need to be long-term stored. Only the initial parameters would&#xA;need to be stored.&#xA;&#xA;Financial privacy for custody&#xA;=============================&#xA;&#xA;One of the concerns raised in [2] is that if all coins at an exchange are&#xA;stored together in the same vault, then attackers would be able to learn about&#xA;access control policies by observing scripts and keys. Some privacy can be&#xA;recovered by using segregated vaults, at the cost of additional setup&#xA;complexity and keeping more data in long-term storage.&#xA;&#xA;However, note that I think vaults are also useful for personal cold storage&#xA;solutions.&#xA;&#xA;Fail-deadly mechanism&#xA;=====================&#xA;&#xA;An early nuclear abort option can be added to these scripts. This idea was&#xA;explored in [2]. This would be a very cold very secret key that would abort the&#xA;re-vaulting procedure and send all coins to a (provably) nonsense key. This&#xA;allows a vault user to destroy the coins instead of continuously monitoring the&#xA;bitcoin blockchain for the rest of his life. The attacker can&#39;t recover their&#xA;cost of attack if they never get the coins, and this eliminates an entire class&#xA;of potential attackers who are directly interested only in financial gain. The&#xA;disadvantage is that if the attacker finds the secret key for the fail-deadly&#xA;mechanism and uses it, then all of the coins are gone forever.&#xA;&#xA;Multisig variations&#xA;===================&#xA;&#xA;The re-vaulting key could be the same key at each layer, or only sometimes the&#xA;same key, or always a unique key stored separately in another secure location.&#xA;&#xA;Additionally, these re-vaulting keys could be subjected to multisig schemes, as&#xA;well as Shamir secret sharing schemes or other secret sharing schemes.&#xA;&#xA;The idea of adding the 4-of-7 multisig component is to avoid griefing&#xA;situations, at the cost of the additional security requirements for the 4-of-7&#xA;multisig group.&#xA;&#xA;Key rotation for vaults&#xA;=======================&#xA;&#xA;Keeping the same hot wallet key for 100 years is not advisable. Rotate the keys&#xA;by setting up a new vault construction and initiating a withdrawal transaction&#xA;from the old vault to the new vault.&#xA;&#xA;Single-use seals&#xA;================&#xA;&#xA;This proposal may have inadvertedly demonstrated a practical way to implement&#xA;Peter Todd&#39;s single-use seals concept [4]. I am hesitant to say so, though,&#xA;because I think he would ask for a more sophisticated way to verify seal&#xA;closure.&#xA;&#xA;Paid defection&#xA;==============&#xA;&#xA;It might be advisable to add small rewards for evidence of defection amongst&#xA;multiparty multisig setups. Besides amounts spendable by individual keys from a&#xA;multisig setup, it may be possible to use a zero-knowledge contingent payment&#xA;for a zero-knowledge statement like: I have a signature s over some message m&#xA;which validates for pubkey pk where pk is a member of the multisig group. Then&#xA;the zkcp transaction would pay for knowledge of defectors. The zkcp procedure&#xA;would require interaction with the defector, while the direct pubkey method&#xA;would not. This is similar to companies paying employees to quit when they&#xA;value the payment over the value of continued employment.&#xA;&#xA;Handling change&#xA;===============&#xA;&#xA;It is important to note that this vault setup is one-time and once-only. There&#xA;must only ever be one deposit into one vault. Also, spending some coins would&#xA;require sending the change amount back into a new vault.  Alternatively,&#xA;upfront work can be done to set a regular withdrawal stipend or assumption&#xA;about how many coins are left, such that the transaction tree can be&#xA;pre-generated for those possibilities, hence cutting down on future vault&#xA;reinitializations. It would also be possible to commit upfront to only ever&#xA;working in some minimum increment number of bitcoin or something.&#xA;&#xA;It is very important to only fund the vault once, and only with the amount that&#xA;was configured when setting up the vault.&#xA;&#xA;References&#xA;==========&#xA;&#xA;[1] https://fc16.ifca.ai/bitcoin/papers/MES16.pdf&#xA;&#xA;[2] http://www0.cs.ucl.ac.uk/staff/P.McCorry/preventing-cryptocurrency-exchange.pdf&#xA;&#xA;[3] http://web.archive.org/web/20180503151920/https://blog.sldx.com/re-imagining-cold-storage-with-timelocks-1f293bfe421f?gi=da99a4a00f67&#xA;&#xA;[4] https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-December/015350.html&#xA;or https://diyhpl.us/wiki/transcripts/building-on-bitcoin/2018/single-use-seals/&#xA;or https://petertodd.org/2016/closed-seal-sets-and-truth-lists-for-privacy&#xA;&#xA;Acknowledgements&#xA;================&#xA;&#xA;* Jeremy Rubin for pointing out something embarrassingly broken in an earlier&#xA;draft.&#xA;&#xA;* Bob McElrath for telling me to use SIGHASH_NOINPUT which I proceeded to&#xA;promptly forget about.&#xA;&#xA;* Andrew Poelstra for the OP_TRUE trick.&#xA;&#xA;* Joe Rayhawk for paid defection.&#xA;&#xA;* Tadge Dryja for pointing out a few differences between SIGHASH_NOINPUT&#xA;proposals.&#xA;&#xA;&#xA;&#xA;Thank you,&#xA;&#xA;- Bryan&#xA;http://heybryan.org/</html></oembed>