Return-Path: Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 4D2C8C002D for ; Sun, 8 May 2022 17:41:28 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 23852409F0 for ; Sun, 8 May 2022 17:41:28 +0000 (UTC) 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 Authentication-Results: smtp4.osuosl.org (amavisd-new); dkim=pass (2048-bit key) header.d=gmail.com Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id NAaDZNwglY_O for ; Sun, 8 May 2022 17:41:25 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.8.0 Received: from mail-pl1-x62c.google.com (mail-pl1-x62c.google.com [IPv6:2607:f8b0:4864:20::62c]) by smtp4.osuosl.org (Postfix) with ESMTPS id 0A366409E7 for ; Sun, 8 May 2022 17:41:24 +0000 (UTC) Received: by mail-pl1-x62c.google.com with SMTP id c9so11208725plh.2 for ; Sun, 08 May 2022 10:41:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=mime-version:references:in-reply-to:from:date:message-id:subject:to; bh=8mU3uoUusU38xUnJxG0AIyJ66L2nQbpPKc/tH5Aecio=; b=is3No1jfBXfoyhMB4uMxJZrH6kMkH9Q10RlWjswbRt1scvnlePvyFIxC8m6wN1Qe+B eCAwNPOh9YpA5zyGzhnnpnLwoZM7bthK9qbH3SgI5Ic+RWcUpUyaa37ldWoMOpim/08H 5m9STvAg+3lLuU+NhmQKW/61sTkcrjD+fNrkeu4w6Tpk2a1XhAqdeBP46wNR5B9lrf6Q th+EZB0LMoTDz1dy5q+jMIizk/zHNHWK4hNZuKaTQfh77UZezbjAX2JLFB7IvmhH8E1t Ka2Gas1T2RlK1+r1ipv+Sl+lJoYdxiJDKNHF8TuoHjDb34SWZlqjHG+havbWuF7yC4wL p+/A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to; bh=8mU3uoUusU38xUnJxG0AIyJ66L2nQbpPKc/tH5Aecio=; b=LJqGcK2KfRTk8WkbvKU4gvC/sx6LGmL1rwmz/YLey4R2xr+XIced07slGKBptk4lVz Lgi6+xGqwZWVdhiWPtmgwss7tNcUYHJbzyMC2DvnEnoeigcJT/gNiBVxH5bZvMVXZeeI +pBvt1+2KGn+8MQK7fFru7Bpjb3flLNFH7Ex7iIn67QWdIVdXrlNrMrFs3V5H6qbg01j 1DELYLyhQw/nbpylpeebZQ5UC5ecGLPah1hQc7fj26ztoF58/wcV8sJLKg+a/cSwXcQk 0bOrRBNm5/JVP3svbh6WCh0cQYPBOQKKwNQLGDNjytp86/uHiqTpoy1w4EWIvdRiA86o fJfA== X-Gm-Message-State: AOAM5308ECBYZ70Vbe+bQO5EmBptAb9AGwDmDoGMEpY7scjUYSNig14d FdLvIFlUXOdROzDm7Pn13h6IFuqDePgDrvjR1qS9bZcf X-Google-Smtp-Source: ABdhPJyb5E7n3HDLNZPu2CEVG1Htp+ipzyOEDhCOz2N3hpvTp9GegMOKmtEaKEWJfI2R7E1JWLJcBzS8419cyEY7jLQ= X-Received: by 2002:a17:90b:1651:b0:1dc:aec3:c17 with SMTP id il17-20020a17090b165100b001dcaec30c17mr14293813pjb.43.1652031684171; Sun, 08 May 2022 10:41:24 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: From: Billy Tetrud Date: Sun, 8 May 2022 12:41:07 -0500 Message-ID: To: Salvatore Ingala , Bitcoin Protocol Discussion Content-Type: multipart/alternative; boundary="000000000000b15a5c05de839916" X-Mailman-Approved-At: Sun, 08 May 2022 18:03:12 +0000 Subject: Re: [bitcoin-dev] Wallet policies for descriptor wallets X-BeenThere: bitcoin-dev@lists.linuxfoundation.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Bitcoin Protocol Discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 08 May 2022 17:41:28 -0000 --000000000000b15a5c05de839916 Content-Type: text/plain; charset="UTF-8" I took a look at the spec for the wallet descriptor format, and I like the concept of having placeholder variables for keys. It reduces the size of the descriptor, makes it substantially easier for a human to read/verify, especially in the future when we have more complex scripts, and provides a nice format for a script template which can make it easier to verify that you're using the same script template as something else (ie besides using different keys). I think the `/**` syntax is an improvement over the current descriptor format, however it is a bit awkward and inflexible. My understanding is that some of this inflexibility comes from the goal of reducing memory usage, and I don't think I have a good enough handle on that part of things to usefully comment. I've put additional comments and suggestions on the format in this github issue . I think it would be very useful to come to agreement on a more flexible format that can support a much broader set of use cases, and can potentially be a widely supported standard. I understand low-ram devices might have a much harder time using more flexible (and complex) formats. On Thu, May 5, 2022 at 9:39 AM Salvatore Ingala via bitcoin-dev < bitcoin-dev@lists.linuxfoundation.org> wrote: > In the implementation work to implement descriptors and miniscript support > in hardware wallets [a][b], I encountered a number of challenges. Some of > them are technical in nature (e.g. due to constraints of embedded > development). Others are related to the attempts of shaping a good user > experience; with bitcoin reaching more people who are not tech-savvy, > self-custody is only as secure as what those newcomers can use easily > enough. > > The main tool that I am using to address some of these challenges is a > layer that sits _on top_ of descriptors/miniscript, while staying very > close to it. Since there is nothing that is vendor-specific in the vast > majority of the approach I'm currently using, I tried to distill it here > for your comments, and will propose a BIP if this is deemed valuable. > > I called the language "wallet policies" (suggestions for a better name are > welcome). I believe an approach based on wallet policies can benefit all > hardware wallets (stateless or not) that want to securely support complex > scripts; moreover, wallet policies are close enough to descriptors that > their integration should be extremely easy for any software wallet that is > currently using descriptors. > > [a]: https://blog.ledger.com/bitcoin-2 - early demo > [b]: https://blog.ledger.com/miniscript-is-coming - miniscript example > > > Salvatore Ingala > > > ====================================================== > > This document starts with a discussion on the motivation for wallet > policies, followed by their formal definition, and some recommendations for > implementations. > > == Rationale == > > Output script descriptors [1] were introduced in bitcoin-core as a way to > represent collections of output scripts. It is a very general and flexible > language, designed to catch all the possible use-cases of bitcoin wallets > (that is, if you know the script and you have the necessary keys, it will > be possible to sign transactions with bitcoin-core's descriptor-based > wallets). > > Unfortunately, descriptors are not a perfect match for the typical usage > of hardware wallets. Most hardware wallets have the following limitations > compared to a general-purpose machine running bitcoin-core: > > - they are embedded devices with limited RAM and computational power; > - they might not be able to import additional private keys (all the keys > are generated from a single seed via [BIP-32]( > https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)); > - they might not have permanent storage (*stateless* hardware wallet > design). > > Moreover, other limitations like the limited size of the screen might > affect what design choices are available in practice. Therefore, minimizing > the size of the information shown on-screen is important for a good user > experience. > > A more native, compact representation of the wallet receive/change would > also benefit the UX of software wallets using descriptors to represent > software wallets using descriptors/miniscript for multisignature or other > complex locking conditions. > > === Security and UX concerns of scripts in hardware wallets === > > For a hardware wallet, allowing the usage of complex scripts presents > challenges in terms of both security and user experience. > > ==== Security issues ==== > > One of the security properties that hardware wallets strive to guarantee > is the following: **as long as the user correctly verifies the information > that is shown on the hardware wallet's screen before approving, no action > can be performed without the user's consent**. > This must hold even in scenarios where the attacker has full control of > the machine that is connected to the hardware wallet, and can execute > arbitrary requests or tamper with the legitimate user's requests. > > Therefore, it is not at all trivial to allow complex scripts, especially > if they contain keys that belong to third parties. > The hardware wallet must guarantee that the user knows precisely *what* > "policy" is being used to spend the funds, and that the "unspent" funds (if > any) will be protected by the same policy. This makes it impossible for an > attacker to surreptitiously modify the policy, therefore stealing or > burning user's funds. > > ==== UX issues ==== > > With miniscript (and taproot trees) allowing substantially more complex > spending policies to be used, it becomes more challenging to make sure that > the user is able _in practice_ to verify the information on the screen. > Therefore, there are two fundamental design goals to strive for: > - Minimize the amount of information that is shown on screen - so that the > user can actually validate it. > - Minimize the number of times the user has to validate such information. > > Designing a secure protocol for the coordination of a descriptor wallet > among distant parties is also a challenging problem that is out of scope in > this document. See BIP-129 [2] for an approach designed for multisignature > wallets. > > === Policy registration as a solution === > > A solution to address the security concerns, and part of the UX concerns, > is to have a *registration* flow for the wallet policy in the hardware > wallet. The "wallet policy" must contain enough information to generate all > the relevant addresses/scripts, and for the hardware wallet to identify the > keys that it controls and that are needed to spend the funds sent to those > addresses. > > Before a new policy is used for the first time, the user will register a > `wallet policy` into the hardware wallet. While the details of the process > are out of scope in this document, the flow should be something similar to > the following: > > 1) The software wallet initiates a _wallet policy registration_ on the > hardware wallet; the information should include the wallet policy, but also > a unique *name* that identifies the policy. > 2) The hardware wallet shows the wallet policy to the user using the > secure screen. > 3) After inspecting the policy and comparing it with a trusted source (for > example a printed backup), the user approves the policy. > 4) If stateful, the hardware wallet persists the policy in its permanent > memory; if stateless, it returns a "proof of registration". > > The details of how to create a proof of registration are out of scope for > this document; using a *message authentication codes* on a hash committing > to the wallet policy, its name and any additional metadata is an effective > solution if correctly executed. > > Once a policy is registered, the hardware wallet can perform the usual > operations securely: > - generating receive and change addresses; > - showing addresses on the secure screen; > - sign transactions spending from a wallet, while correctly identifying > change addresses and computing the transaction fees. > > Before any of the actions mentioned above, the hardware wallet will > retrieve the policy from its permanent storage if stateful; if stateless it > will validate the _proof of registration_ before using the wallet policy > provided by the client. > Once the previously registered policy is correctly identified and approved > by the user (for example by its name), and *as long as the policy > registration was executed securely*, hardware wallets can provide a user > experience similar to the usual one for single-signature transactions. > > === Avoiding blowup in descriptor size === > > While reusing a pubkey in different branches of a miniscript is explicitly > forbidden by miniscript (as it has certain negative security implications), > it is still reasonable to reuse the same *xpub* in multiple places, albeit > with different final steps of derivation (so that the actual pubkeys that > are used in the script are indeed different). > > For example, using Taproot, a *3*-of-*5* multisignature wallet could use: > - a key path with a 5-of-5 MuSig > - a script tree with a tree of 10 different 3-of-3 MuSig2 scripts, that > are generated, plus a leaf with a fallback *3*-of-*5* multisignature using > plain multisignature (with `OP_CHECKSIGADD`). > > This could look similar to: > > ``` > tr(musig2(xpubA,xpubB,xpubC,xpubD,xpubE)/<0;1>/*), { > { > { > pk(musig2(xpubA,xpubB,xpubC)/<2;3>/*), > { > pk(musig2(xpubA,xpubB,xpubD)/<4;5>/*) > pk(musig2(xpubA,xpubB,xpubE)/<6;7>/*), > } > }, > { > pk(musig2(xpubA,xpubC,xpubD)/<8;9>/*), > { > pk(musig2(xpubA,xpubC,xpubE)/<10;11>/*), > pk(musig2(xpubA,xpubD,xpubE)/<12;13>/*) > } > } > }, > { > { > pk(musig2(xpubB,xpubC,xpubD)/<14;15>/*), > pk(musig2(xpubB,xpubC,xpubE)/<16;17>/*) > }, > { > pk(musig2(xpubB,xpubD,xpubE)/<18;19>/*), > { > pk(musig2(xpubC,xpubD,xpubE)/<20;21>/*), > sortedmulti_a(3, > xpubA/<22;23>/*, > xpubB/<22;23>/*, > xpubC/<22;23>/*, > xpubD/<22;23>/*, > xpubE/<22;23>/*) > } > } > } > }) > ``` > > Note that each root xpub appears 8 times. With xpubs being up to 118 bytes > long, the length of the full descriptor can get extremely long (the problem > gets *exponentially* worse with larger multisignature schemes). > > Replacing the common part of the key with a short key placeholder and > moving the key expression separately helps to keep the size of the wallet > policy small, which is crucial to allow human inspection in the > registration flow. > > === Restrictions on the supported descriptors ==== > > The policy language proposed in this document purposely targets only a > stricter subset of the output descriptors language, and it attempts to > generalize in the most natural way the approach that is already used for > single-signature *accounts* (as described in BIP-44 [3], BIP-49 [4], BIP-84 > [5], or BIP-86 [6]), or in multisignature setups (see for example BIP-48 > [7] and BIP-87 [8]). > > Unlike the BIPs mentioned above, it is not tied to any specific script > template, as it applies to arbitrary scripts that can be represented with > descriptors and miniscript. > > Supporting only a reduced feature set when compared to output descriptors > helps in implementations (especially on hardware wallets), while attempting > to capture all the common use cases. More features can be added in the > future if motivated by real world necessity. > > By keeping the structure of the wallet policy language very close to that > of descriptors, it should be straightforward to: > - write wallet policy parsers; > - extract the descriptors defined by a wallet policy; > - convert a pair of descriptors describing a wallet "account" used in > current implementations into the corresponding wallet policy. > > > == Wallet policies == > > This section formally defines wallet policies, and how they relate to > output script descriptors. > > === Formal definition === > > A wallet policy is composed by a wallet descriptor template, together with > a vector of key information items. > > ==== Wallet descriptor template ==== > > A wallet descriptor template is a `SCRIPT` expression. > > `SCRIPT` expressions: > - `sh(SCRIPT)` (top level only): P2SH embed the argument. > - `wsh(SCRIPT)` (top level or inside `sh` only): P2WSH embed the argument. > - `pkh(KP)` (not inside `tr`): P2PKH output for the given public key (use > `addr` if you only know the pubkey hash). > - `wpkh(KP)` (top level or inside `sh` only): P2WPKH output for the given > compressed pubkey. > - `multi(k,KP_1,KP_2,...,KP_n)`: k-of-n multisig script. > - `sortedmulti(k,KP_1,KP_2,...,KP_n)`: k-of-n multisig script with keys > sorted lexicographically in the resulting script. > - `tr(KP)` or `tr(KP,TREE)` (top level only): P2TR output with the > specified key as internal key, and optionally a tree of script paths. > - any valid miniscript template (inside `wsh` or `tr` only). > > `TREE` expressions: > - any `SCRIPT` expression > - An open brace `{`, a `TREE` expression, a comma `,`, a `TREE` > expression, and a closing brace `}` > > Note: "miniscript templates" are not formally defined in this version of > the document, but it is straightforward to adapt this approach. > > `KP` expressions (key placeholders) consist of > - a single character `@` > - followed by a non-negative decimal number, with no leading zeros (except > for `@0`). > - possibly followed by either: > - the string `/**`, or > - a string of the form `//*`, for two distinct decimal numbers > `NUM` representing unhardened derivations > > The `/**` in the placeholder template represents commonly used paths for > receive/change addresses, and is equivalent to `<0;1>`. > > The placeholder `@i` for some number *i* represents the *i*-th key in the > vector of key origin information (which must be of size at least *i* + 1, > or the wallet policy is invalid). > > ==== Key informations vector ==== > > Each element of the key origin information vector is a `KEY` expression. > > - Optionally, key origin information, consisting of: > - An open bracket `[` > - Exactly 8 hex characters for the fingerprint of the master key from > which this key is derived from (see [BIP32]( > https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) for > details) > - Followed by zero or more `/NUM'` path elements to indicate hardened > derivation steps between the fingerprint and the xpub that follows > - A closing bracket `]` > - Followed by the actual key, which is either > - a hex-encoded pubkey, which is either > - inside `wpkh` and `wsh`, only compressed public keys are permitted > (exactly 66 hex characters starting with `02` or `03`. > - inside `tr`, x-only pubkeys are also permitted (exactly 64 hex > characters). > - a serialized extended public key (`xpub`) (as defined in [BIP 32]( > https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)) > > The placeholder `@i` for some number *i* represents the *i*-th key in the > vector of key orIgin information (which must be of size at least *i* + 1, > or the wallet policy is invalid). > > The policy template is invalid if any placeholder `@i` has derivation > steps while the corresponding `(i+1)`-th element of the keys vector is not > an xpub. > > ==== Additional rules ==== > > The wallet policy is invalid if any placeholder expression with additional > derivation steps is used when the corresponding key information is not an > xpub. > > The key information vector *should* be ordered so that placeholder `@i` > never appear for the first time before an occurrence of `@j` for some `j < > i`; for example, the first placeholder is always `@0`, the next one is > `@1`, etc. > > === Descriptor derivation === > > From a wallet descriptor template (and the associated vector of key > informations), one can therefore obtain the 1-dimensional descriptor for > receive and change addresses by: > > - replacing each key placeholder with the corresponding key origin > information; > - replacing every `/**` with `/0/*` for the receive descriptor, and > `/1/*` for the change descriptor; > - replacing every `/` with `/M` for the receive descriptor, and `/N` > for the change descriptor. > > For example, the wallet descriptor `pkh(@0/**)` with key information > `["[d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"]` > produces the following two descriptors: > > - Receive descriptor: > `pkh([d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*)` > > - Change descriptor: > `pkh([d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*)` > > === Implementation guidelines === > > Implementations must not necessarily implement all of the possible wallet > policies defined by this standard, but it is recommended to clearly > document any limitation. > > Implementations can add additional metadata that is stored together with > the wallet policy for the purpose of wallet policy registration and later > usage. Metadata can be vendor-specific and is out of the scope of this > document. > > Any implementation in a general-purpose software wallet allowing arbitrary > scripts (or any scripts that involve external cosigners) should put great > care into a process for backing up a wallet policy. In fact, unlike typical > single-signature scenarios, the seed alone is no longer enough to discover > wallet policies with existing funds, and the loss of the backup is likely > to lead to permanent loss of funds. > > Avoiding key reuse among different wallet accounts is also extremely > important, but out of scope for this document. > > == Examples == > > Some examples of wallet descriptor templates (vectors of keys omitted for > simplicity): > - Template for a native segwit account: > wpkh(@0/**) > - Template for a taproot BIP86 account: > tr(@0/**) > - Template for a native segwit 2-of-3: > wsh(sortedmulti(2,@0/**,@1/**,@2/**)) > - Template with miniscript for "1 of 2 equally likely keys": > wsh(or_b(pk(@0/**),s:pk(@1/**))) > > More examples (esp. targeting miniscript on taproot) will be added in the > future. > > == References == > > * [1] - Output Script Descriptors: > https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md > * [2] - BIP-129 (Bitcoin Secure Multisig Setup): > https://github.com/bitcoin/bips/blob/master/bip-0129.mediawiki > * [3] - BIP-44: > https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki > * [4] - BIP-49: > https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki > * [5] - BIP-84: > https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki > * [6] - BIP-86: > https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki > * [7] - BIP-48: > https://github.com/bitcoin/bips/blob/master/bip-0048.mediawiki > * [8] - BIP-87: > https://github.com/bitcoin/bips/blob/master/bip-0087.mediawiki > > _______________________________________________ > bitcoin-dev mailing list > bitcoin-dev@lists.linuxfoundation.org > https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev > --000000000000b15a5c05de839916 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
I took a look at the spec for the wallet descriptor format= , and I like the concept of having placeholder variables for keys. It reduc= es the size of the descriptor,=C2=A0makes it substantially easier for a hum= an to read/verify,=C2=A0especially in the future when we have more complex = scripts,=C2=A0and provides a nice=C2=A0format for a script template which c= an make it easier to verify that you're using the same script template = as something else (ie besides using different keys). I think the `/**` synt= ax is an improvement over the current descriptor format, however it is a bi= t awkward and inflexible. My understanding is that some of this inflexibili= ty comes from the goal of reducing memory usage, and I don't think I ha= ve a good enough handle on that part of things to usefully comment. I'v= e put additional comments and suggestions on the format in this gi= thub issue.=C2=A0

I think it would=C2=A0be very usef= ul to come to agreement on a more flexible format that can support a much b= roader set of use cases, and can potentially be a widely supported standard= . I understand low-ram devices might have a much harder time using more fle= xible (and complex) formats.







On Thu, May 5, 2022 at 9:3= 9 AM Salvatore Ingala via bitcoin-dev <bitcoin-dev@lists.linuxfoundation= .org> wrote:
In the implementation work to implement descriptors an= d miniscript support in hardware wallets [a][b], I encountered a number of = challenges. Some of them are technical in nature (e.g. due to constraints o= f embedded development). Others are related to the attempts of shaping a go= od user experience; with bitcoin reaching more people who are not tech-savv= y, self-custody is only as secure as what those newcomers can use easily en= ough.

The main tool that I am using to address some of these challen= ges is a layer that sits _on top_ of descriptors/miniscript, while staying = very close to it. Since there is nothing that is vendor-specific in the vas= t majority of the approach I'm currently using, I tried to distill it h= ere for your comments, and will propose a BIP if this is deemed valuable.
I called the language "wallet policies" (suggestions for a = better name are welcome). I believe an approach based on wallet policies ca= n benefit all hardware wallets (stateless or not) that want to securely sup= port complex scripts; moreover, wallet policies are close enough to descrip= tors that their integration should be extremely easy for any software walle= t that=C2=A0is currently using descriptors.

[a]: https://blog.ledger.com/bitcoi= n-2 - early demo
[b]:=C2=A0https://blog.ledger.com/miniscript-is-co= ming - miniscript example


Salvatore Ingala

=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

This document starts with a = discussion on the motivation for wallet policies, followed by their formal = definition, and some recommendations for implementations.

=3D= =3D Rationale =3D=3D

Output script descriptors [1] were i= ntroduced in bitcoin-core as a way to represent collections of output scrip= ts. It is a very general and flexible language, designed to catch all the p= ossible use-cases of bitcoin wallets (that is, if you know the script and y= ou have the necessary keys, it will be possible to sign transactions with b= itcoin-core's descriptor-based wallets).

Unfortunately, descript= ors are not a perfect match for the typical usage of hardware wallets. Most= hardware wallets have the following limitations compared to a general-purp= ose machine running bitcoin-core:

- they are embedded devices with l= imited RAM and computational power;
- they might not be able to import a= dditional private keys (all the keys are generated from a single seed via [= BIP-32](https://github.com/bitcoin/bips/blob/master/bip-= 0032.mediawiki));
- they might not have permanent storage (*stateles= s* hardware wallet design).

Moreover, other limitations like the lim= ited size of the screen might affect what design choices are available in p= ractice. Therefore, minimizing the size of the information shown on-screen = is important for a good user experience.

A more native, compact repr= esentation of the wallet receive/change would also benefit the UX of softwa= re wallets using descriptors to represent software wallets using descriptor= s/miniscript for multisignature or other complex locking conditions.
=3D=3D=3D Security and UX concerns of scripts in hardware wallets =3D=3D= =3D

For a hardware wallet, allowing the usage of complex = scripts presents challenges in terms of both security and user experience.<= br>
=3D=3D=3D=3D Security issues =3D=3D=3D=3D

One of the s= ecurity properties that hardware wallets strive to guarantee is the followi= ng: **as long as the user correctly verifies the information that is shown = on the hardware wallet's screen before approving, no action can be perf= ormed without the user's consent**.
This must hold even in scenarios= where the attacker has full control of the machine that is connected to th= e hardware wallet, and can execute arbitrary requests or tamper with the le= gitimate user's requests.

Therefore, it is not at all trivial to= allow complex scripts, especially if they contain keys that belong to thir= d parties.
The hardware wallet must guarantee that the user knows precis= ely *what* "policy" is being used to spend the funds, and that th= e "unspent" funds (if any) will be protected by the same policy. = This makes it impossible for an attacker to surreptitiously modify the poli= cy, therefore stealing or burning user's funds.

=3D=3D=3D=3D UX = issues =3D=3D=3D=3D

With miniscript (and taproot trees) allow= ing substantially more complex spending policies to be used, it becomes mor= e challenging to make sure that the user is able _in practice_ to verify th= e information on the screen. Therefore, there are two fundamental design go= als to strive for:
- Minimize the amount of information that is shown on= screen - so that the user can actually validate it.
- Minimize the numb= er of times the user has to validate such information.

Designing a s= ecure protocol for the coordination of a descriptor wallet among distant pa= rties is also a challenging problem that is out of scope in this document. = See BIP-129 [2] for an approach designed for multisignature wallets.
=3D=3D=3D Policy registration as a solution =3D=3D=3D

A solu= tion to address the security concerns, and part of the UX concerns, is to h= ave a *registration* flow for the wallet policy in the hardware wallet. The= "wallet policy" must contain enough information to generate all = the relevant addresses/scripts, and for the hardware wallet to identify the= keys that it controls and that are needed to spend the funds sent to those= addresses.

Before a new policy is used for the first time, the user= will register a `wallet policy` into the hardware wallet. While the detail= s of the process are out of scope in this document, the flow should be some= thing similar to the following:

1) The software wallet initiates a _= wallet policy registration_ on the hardware wallet; the information should = include the wallet policy, but also a unique *name* that identifies the pol= icy.
2) The hardware wallet shows the wallet policy to the user using th= e secure screen.
3) After inspecting the policy and comparing it with a = trusted source (for example a printed backup), the user approves the policy= .
4) If stateful, the hardware wallet persists the policy in its permane= nt memory; if stateless, it returns a "proof of registration".
The details of how to create a proof of registration are out of scope = for this document; using a *message authentication codes* on a hash committ= ing to the wallet policy, its name and any additional metadata is an effect= ive solution if correctly executed.

Once a policy is registered, the= hardware wallet can perform the usual operations securely:
- generating= receive and change addresses;
- showing addresses on the secure screen;=
- sign transactions spending from a wallet, while correctly identifying= change addresses and computing the transaction fees.

Before any of = the actions mentioned above, the hardware wallet will retrieve the policy f= rom its permanent storage if stateful; if stateless it will validate the _p= roof of registration_ before using the wallet policy provided by the client= .
Once the previously registered policy is correctly identified and appr= oved by the user (for example by its name), and *as long as the policy regi= stration was executed securely*, hardware wallets can provide a user experi= ence similar to the usual one for single-signature transactions.

=3D= =3D=3D Avoiding blowup in descriptor size =3D=3D=3D

While reu= sing a pubkey in different branches of a miniscript is explicitly forbidden= by miniscript (as it has certain negative security implications), it is st= ill reasonable to reuse the same *xpub* in multiple places, albeit with dif= ferent final steps of derivation (so that the actual pubkeys that are used = in the script are indeed different).

For example, using Taproot, a *= 3*-of-*5* multisignature wallet could use:
- a key path with a 5-of-5 Mu= Sig
- a script tree with a tree of 10 different 3-of-3 MuSig2 scripts, t= hat are generated, plus a leaf with a fallback *3*-of-*5* multisignature us= ing plain multisignature (with `OP_CHECKSIGADD`).

This could look si= milar to:

```
tr(musig2(xpubA,xpubB,xpubC,xpubD,xpubE)/<0;1>= ;/*), {
=C2=A0 {
=C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 pk(musig2(xp= ubA,xpubB,xpubC)/<2;3>/*),
=C2=A0 =C2=A0 =C2=A0 {
=C2=A0 =C2=A0= =C2=A0 =C2=A0 pk(musig2(xpubA,xpubB,xpubD)/<4;5>/*)
=C2=A0 =C2=A0= =C2=A0 =C2=A0 pk(musig2(xpubA,xpubB,xpubE)/<6;7>/*),
=C2=A0 =C2= =A0 =C2=A0 }
=C2=A0 =C2=A0 },
=C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0= pk(musig2(xpubA,xpubC,xpubD)/<8;9>/*),
=C2=A0 =C2=A0 =C2=A0 {
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 pk(musig2(xpubA,xpubC,xpubE)/<10;11>/*),<= br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 pk(musig2(xpubA,xpubD,xpubE)/<12;13>/*= )
=C2=A0 =C2=A0 =C2=A0 }
=C2=A0 =C2=A0 }
=C2=A0 },
=C2=A0 {
= =C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 pk(musig2(xpubB,xpubC,xpubD)/<14= ;15>/*),
=C2=A0 =C2=A0 =C2=A0 pk(musig2(xpubB,xpubC,xpubE)/<16;17&= gt;/*)
=C2=A0 =C2=A0 },
=C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 pk(mu= sig2(xpubB,xpubD,xpubE)/<18;19>/*),
=C2=A0 =C2=A0 =C2=A0 {
=C2= =A0 =C2=A0 =C2=A0 =C2=A0 pk(musig2(xpubC,xpubD,xpubE)/<20;21>/*),
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 sortedmulti_a(3,
=C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 xpubA/<22;23>/*,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 xpubB/= <22;23>/*,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 xpubC/<22;23>/= *,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 xpubD/<22;23>/*,
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 xpubE/<22;23>/*)
=C2=A0 =C2=A0 =C2=A0 = }
=C2=A0 =C2=A0 }
=C2=A0 }
})
```

Note that each root xp= ub appears 8 times. With xpubs being up to 118 bytes long, the length of th= e full descriptor can get extremely long (the problem gets *exponentially* = worse with larger multisignature schemes).

Replacing the common part= of the key with a short key placeholder and moving the key expression sepa= rately helps to keep the size of the wallet policy small, which is crucial = to allow human inspection in the registration flow.

=3D=3D=3D Restri= ctions on the supported descriptors =3D=3D=3D=3D

The policy language= proposed in this document purposely targets only a stricter subset of the = output descriptors language, and it attempts to generalize in the most natu= ral way the approach that is already used for single-signature *accounts* (= as described in BIP-44 [3], BIP-49 [4], BIP-84 [5], or BIP-86 [6]), or in m= ultisignature setups (see for example BIP-48 [7] and BIP-87 [8]).

Unlike the BIPs mentioned above, it is not tied to any specific script= template, as it applies to arbitrary scripts that can be represented with = descriptors and miniscript.

Supporting only a reduced feature set wh= en compared to output descriptors helps in implementations (especially on h= ardware wallets), while attempting to capture all the common use cases. Mor= e features can be added in the future if motivated by real world necessity.=

By keeping the structure of the wallet policy language very close t= o that of descriptors, it should be straightforward to:
- write wallet p= olicy parsers;
- extract the descriptors defined by a wallet policy;
= - convert a pair of descriptors describing a wallet "account" use= d in current implementations into the corresponding wallet policy.

<= br>=3D=3D Wallet policies =3D=3D

This section formally define= s wallet policies, and how they relate to output script descriptors.
<= div>
=3D=3D=3D Formal definition =3D=3D=3D

A wa= llet policy is composed by a wallet descriptor template, together with a ve= ctor of key information items.

=3D=3D=3D=3D Wallet descriptor templa= te =3D=3D=3D=3D

A wallet descriptor template is a `SCRIPT` expressio= n.

`SCRIPT` expressions:
- `sh(SCRIPT)` (top level only): P2SH em= bed the argument.
- `wsh(SCRIPT)` (top level or inside `sh` only): P2WSH= embed the argument.
- `pkh(KP)` (not inside `tr`): P2PKH output for the= given public key (use `addr` if you only know the pubkey hash).
- `wpkh= (KP)` (top level or inside `sh` only): P2WPKH output for the given compress= ed pubkey.
- `multi(k,KP_1,KP_2,...,KP_n)`: k-of-n multisig script.
-= `sortedmulti(k,KP_1,KP_2,...,KP_n)`: k-of-n multisig script with keys sort= ed lexicographically in the resulting script.
- `tr(KP)` or `tr(KP,TREE)= ` (top level only): P2TR output with the specified key as internal key, and= optionally a tree of script paths.
- any valid miniscript templa= te (inside `wsh` or `tr` only).

`TREE` expressions:
- any = `SCRIPT` expression
- An open brace `{`, a `TREE` expression, a comma `,= `, a `TREE` expression, and a closing brace `}`

Note: "min= iscript templates" are not formally=C2=A0defined in this version of th= e document, but it is straightforward=C2=A0to adapt this approach.

`KP` expressions (key placeholders) consist of
- a single character= `@`
- followed by a non-negative decimal number, with no leading zeros = (except for `@0`).
- possibly followed by either:
=C2=A0 - the string= =C2=A0`/**`, or
=C2=A0 - a string of the form `/<NUM;NUM>/*`, for= two distinct decimal numbers `NUM` representing unhardened derivations
=
The `/**` in the placeholder template represents commonly used paths fo= r receive/change addresses, and is equivalent to `<0;1>`.

The = placeholder `@i` for some number *i* represents the *i*-th key in the vecto= r of key origin information (which must be of size at least *i* + 1, or the= wallet policy is invalid).

=3D=3D=3D=3D Key i= nformations vector =3D=3D=3D=3D

Each element of the key origin infor= mation vector is a `KEY` expression.

- Optionally, key origin inform= ation, consisting of:
=C2=A0 - An open bracket `[`
=C2=A0 - Exactly 8= hex characters for the fingerprint of the master key from which this key i= s derived from (see [BIP32](https://github.com/bitcoin/bi= ps/blob/master/bip-0032.mediawiki) for details)
=C2=A0 - Followed by= zero or more `/NUM'` path elements to indicate hardened derivation ste= ps between the fingerprint and the xpub that follows
=C2=A0 - A closing = bracket `]`
- Followed by the actual key, which is either
=C2=A0 - a = hex-encoded pubkey, which is either
=C2=A0 =C2=A0 - inside=C2=A0`wpkh`= =C2=A0and=C2=A0`wsh`, only compressed public keys are permitted (exactly 66= hex characters starting with `02` or `03`.
=C2=A0 =C2=A0 - inside `tr`,= x-only pubkeys are also permitted (exactly 64 hex characters).
=C2=A0 -= a serialized extended public key (`xpub`) (as defined in [BIP 32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki<= /a>))

The placeholder `@i` for some number *i* represents the *i*-th= key in the vector of key orIgin information=C2=A0(which must be of size at= least *i* + 1, or the wallet policy is invalid).

The policy templat= e is invalid if any placeholder `@i` has derivation steps while the corresp= onding `(i+1)`-th element of the keys vector is not an xpub.

=3D=3D= =3D=3D Additional rules =3D=3D=3D=3D

From a wall= et descriptor template (and the associated vector of key informations), one= can therefore obtain the 1-dimensional descriptor for receive and change a= ddresses by:

- replacing each key placeholder with the corresponding= key origin information;
- replacing every `/**` =C2=A0with `/0/*` for t= he receive descriptor, and `/1/*` for the change descriptor;
- replacing= every `/<M,N>` with =C2=A0`/M` for the receive descriptor, and `/N` = for the change descriptor.

For example, the wallet descriptor `pkh(@= 0/**)` with key information `["[d34db33f/44'/0'/0']xpub6ER= ApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4AL= HY2grBGRjaDMzQLcgJvLJuZZvRcEL"]` produces the following two descriptor= s:

- Receive descriptor: `pkh([d34db33f/44'/0'/0']xpub6E= RApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4A= LHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*)`

- Change descriptor: `pkh([d34d= b33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVH= QKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*)`
=3D=3D=3D Implementation guidelines =3D=3D=3D

Implementatio= ns must not necessarily implement all of the possible wallet policies defin= ed by this standard, but it is recommended to clearly document any limitati= on. =C2=A0

Implementations can add additional metadata that is store= d together with the wallet policy for the purpose of wallet policy registra= tion and later usage. Metadata can be vendor-specific and is out of the sco= pe of this document.

Any implementation in a general-purpose softwar= e wallet allowing arbitrary scripts (or any scripts that involve external c= osigners) should put great care into a process for backing up a wallet poli= cy. In fact, unlike typical single-signature scenarios, the seed alone is n= o longer enough to discover wallet policies with existing funds, and the lo= ss of the backup is likely to lead to permanent loss of funds.

Avoid= ing key reuse among different wallet accounts is also extremely important, = but out of scope for this document.

=3D=3D Examples =3D=3D

So= me examples of wallet descriptor templates (vectors of keys omitted for sim= plicity):

<= div>

* [2] - BIP-129 = (Bitcoin Secure Multisig Setup): https://github.com/bitco= in/bips/blob/master/bip-0129.mediawiki
* [3] - BIP-44: https://github.com/bitcoin/bips/blob/master/bip-0044.mediaw= iki

_______________________________________________
bitcoin-dev mailing list
= bitcoin-dev@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mail= man/listinfo/bitcoin-dev
--000000000000b15a5c05de839916--