What changed, and why it matters
This commit only adds and reorganizes user and developer documentation. No program code, build scripts, tests, or cryptographic logic were changed. It is not a security patch and does not introduce or fix any vulnerability.
No security action required. Treat as routine documentation update.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit f32a3610bc4e28703b1ac7256daaf73a7af34ec7 is a documentation-only change for the Ledger Bitcoin app. It adds two new markdown guides (doc/features.md and doc/integration.md), updates README.md to link to them, and trims doc/wallet.md to remove duplication with BIP-388. The diff contains no source-code modifications, no protocol changes, and no functional behavior changes.
Changed components
Inspect captured patch +344 / −165
diff --git a/README.md b/README.md
index 088e359..18098c0 100644
--- a/README.md
+++ b/README.md
@@ -138,15 +138,20 @@ python3 -m ledgerblue.runScript --scp --fileName bin/app.apdu --elfFile bin/app.
## Documentation
-For many use cases, the code examples provided in the following client libraries might be sufficient to get started:
+If you want to understand what the app does or build an integration on top of an existing client library, start here:
+- [features.md](doc/features.md): Overview of the app's features and the account/script types it supports.
+- [integration.md](doc/integration.md): Concepts and security model for integrators — wallet policies, registration, and on-device verification.
+
+For many use cases, the code examples provided in the following client libraries are enough to get started:
- [Python client library](bitcoin_client)
- [JavaScript client library](bitcoin_client_js)
- [Rust client library](bitcoin_client_rs)
-If you need to go deeper into the rabbit hole 🐇🕳️, refer to the following documents:
+If you need to go deeper into the rabbit hole 🐇🕳️ (for example to implement a client library or work at the protocol level), refer to the following documents:
- [bitcoin.md](doc/bitcoin.md): Low-level documentation of the Bitcoin app's communication protocol and commands.
+- [wallet.md](doc/wallet.md): Formal definition of the wallet policy language, its serialization, and the supported scripts.
- [merkle.md](doc/merkle.md): Advanced details on techniques used in the Bitcoin app's secured and scalable communication protocol.
-- [wallet.md](doc/wallet.md): Information on the types of scripts supported by the Ledger Bitcoin app and the security requirements for multi-user or multi-key spending policies.
+- [musig.md](doc/musig.md): Details of the MuSig2 implementation and its on-device state management.
- [debugging.md](doc/debugging.md): Guidance on how to diagnose and resolve issues.
## Tests
diff --git a/doc/features.md b/doc/features.md
new file mode 100644
index 0000000..d03e1d5
--- /dev/null
+++ b/doc/features.md
@@ -0,0 +1,100 @@
+# Features and capabilities
+
+This document gives a high-level overview of what the Ledger Bitcoin app can do. It is
+aimed at technical users and developers who want to understand the app's features, or
+build an integration on top of one of the existing client libraries, without needing the
+details of the wire protocol.
+
+If you are implementing a client library from scratch, or need the exact byte-level
+encoding of each command, refer instead to [bitcoin.md](bitcoin.md).
+
+## Overview
+
+The Bitcoin app is a **stateless signer** that runs on a Ledger device. It never holds wallet
+state between commands. The host application drives it through one of the client libraries, and
+every sensitive operation (revealing a public key, registering a wallet, showing an address,
+signing a transaction or a message) is confirmed by the user on the device's **trusted screen**.
+
+Because the device is stateless, the host (typically, a software wallet) is always the source of
+wallet and transaction information.
+
+The concepts behind this model — wallet policies, registration, and on-device
+verification — are described in [integration.md](integration.md).
+
+## Supported operations
+
+Each operation maps to a method in the client libraries
+([Python](../bitcoin_client), [JavaScript](../bitcoin_client_js),
+[Rust](../bitcoin_client_rs)); see their READMEs for ready-to-run code examples.
+
+| Operation | What it does |
+|-----------|--------------|
+| Get master key fingerprint | Returns the 4-byte fingerprint of the master key, used in key origin information. |
+| Get extended public key | Returns the `xpub` at a given BIP-32 path, optionally displaying it on-screen for verification. |
+| Register a wallet policy | Has the user approve a wallet policy on the trusted screen and returns an HMAC that authorizes future use of that policy. |
+| Get / verify a wallet address | Derives an address for a registered or default wallet, optionally displaying it on-screen so the user can verify it. |
+| Sign a transaction | Signs a PSBT and returns the partial signatures it can produce. |
+| Sign a message | Signs an arbitrary message using the Bitcoin signed-message format, at a given BIP-32 path. |
+
+## Supported account and script types
+
+The app describes accounts using **wallet policies** (see
+[integration.md](integration.md) and [wallet.md](wallet.md)). The script types below are
+supported.
+
+### Single-key standard accounts
+
+Four single-key account types — legacy, nested SegWit, native SegWit, and taproot, following
+BIP-44/49/84/86 — can be used **without registration**. These are the *default wallets*; see
+[wallet.md](wallet.md#default-wallets) for the exact templates, derivation paths, and bounds, and
+[integration.md](integration.md) for the default-vs-registered distinction.
+
+### Multisig
+
+Multisig is supported across legacy, nested SegWit, native SegWit, and taproot (as a
+script path), in both `multi` and `sortedmulti` forms. See [wallet.md](wallet.md#supported-scripts)
+for the exact set of templates.
+
+### Taproot
+
+The app supports `tr(...)` outputs with both **keypath** and **script-path** spends, and
+arbitrary trees of script leaves.
+
+### Miniscript
+
+[Miniscript](https://github.com/bitcoin/bips/blob/master/bip-0379.md) is supported inside top-level
+`wsh(...)` and inside taproot script leaves. It allows expressing richer spending conditions than
+plain multisig — for example timelocks, recovery/backup keys, or threshold policies that
+change over time. See [integration.md](integration.md) for an example.
+
+### MuSig2
+
+Taproot policies may use `musig()` key expressions to aggregate several keys into a
+single on-chain key, following [BIP-0327](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki).
+The signing-flow details are covered in [musig.md](musig.md).
+
+## Networks
+
+The app is built per network: the mainnet build is named **Bitcoin**, and the testnet
+build is named **Bitcoin Test**. They are ***separate applications***.
+
+The **Bitcoin Test** app can be used for all test networks, including Bitcoin Core's regtest.
+Note, however, that SegWit (and taproot) addresses are shown on-screen and returned to the
+host using the human readable part `tb1`, while bitcoin-core uses `bcrt`.
+
+## Version and feature compatibility
+
+This documentation describes the current (v2) protocol. Some features might not be available
+in older versions of the app. Consult the [CHANGELOG.md](../CHANGELOG.md) to check when a
+specific capability became available.
+
+## Where to go next
+
+- **Build something** → the client library READMEs
+ ([Python](../bitcoin_client), [JavaScript](../bitcoin_client_js),
+ [Rust](../bitcoin_client_rs)) contain runnable examples.
+- **Understand the model** → [integration.md](integration.md) explains wallet policies,
+ registration, and the security model.
+- **Wallet policy language** → [wallet.md](wallet.md) and
+ [BIP-388](https://github.com/bitcoin/bips/blob/master/bip-0388.mediawiki).
+- **Wire protocol** → [bitcoin.md](bitcoin.md).
diff --git a/doc/integration.md b/doc/integration.md
new file mode 100644
index 0000000..6c2d324
--- /dev/null
+++ b/doc/integration.md
@@ -0,0 +1,159 @@
+# Integration concepts and security model
+
+This document explains the concepts an integrator needs in order to build on top of the
+Ledger Bitcoin app using one of the existing client libraries
+([Python](../bitcoin_client), [JavaScript](../bitcoin_client_js),
+[Rust](../bitcoin_client_rs)). It complements the feature overview in
+[features.md](features.md) and the protocol-level specifications in
+[bitcoin.md](bitcoin.md) and [wallet.md](wallet.md).
+
+## The device is stateless
+
+The app does **not** persist any wallet-related or transaction-related information between
+calls. There is no notion of "the wallet currently loaded on the device": every request that
+involves an account (deriving an address, signing a transaction) must carry the full
+description of that account, supplied by the host.
+
+This means the **host application is responsible for storing** the account definitions
+(and, for registered wallets, the authorization HMAC described below) and providing them
+on each call. The host is *not* trusted, however: it merely supplies the information the
+device needs. Anything that matters for security is verified by the user on the device's
+trusted screen (see [On-device verification](#on-device-verification-and-the-trusted-screen)
+below), so a compromised host cannot make the device sign or display something the user
+did not approve.
+
+## Wallet policies
+
+An account is described by a **wallet policy** — the representation standardized in
+[BIP-388](https://github.com/bitcoin/bips/blob/master/bip-0388.mediawiki). It pairs a
+*descriptor template*, which captures the script's shape with keys replaced by
+placeholders (`@0`, `@1`, …), with a *key information vector* that holds the actual keys
+(`xpub`s) and their key origin information. [wallet.md](wallet.md) defines the format,
+grammar, serialization, and implementation-specific restrictions.
+
+Separating the template from the keys lets the device recognize the *shape* of a policy
+independently of the specific keys, and lets `sortedmulti`-style policies be order
+independent.
+
+### Examples
+
+A single-key taproot account (a *default wallet*, see below — no registration needed):
+
+```
+tr(@0/**)
+keys: ["[f5acc2fd/86'/0'/0']xpub6C..."]
+```
+
+Other more complex wallet types must be registered before use.
+
+This is a 2-of-3 native SegWit multisig:
+
+```
+wsh(sortedmulti(2,@0/**,@1/**,@2/**))
+keys: [
+ "[f5acc2fd/48'/0'/0'/2']xpub6E...", // this device
+ "[1a2b3c4d/48'/0'/0'/2']xpub6E...", // cosigner 2
+ "[5e6f7a8b/48'/0'/0'/2']xpub6E..." // cosigner 3
+]
+```
+
+The following is a miniscript "recovery vault" — spendable by the primary key at any time, or by a backup
+key after a relative timelock of `65535` blocks:
+
+```
+wsh(or_d(pk(@0/**),and_v(v:pkh(@1/**),older(65535))))
+keys: [
+ "[f5acc2fd/48'/0'/0'/2']xpub6E...", // primary key
+ "[1a2b3c4d/48'/0'/0'/2']xpub6E..." // recovery key
+]
+```
+
+## Default vs registered wallets
+
+- **Default (standard) wallet accounts** are the four single-key account types
+ (`pkh`, `sh(wpkh)`, `wpkh`, `tr`), with the corresponding standard derivation paths
+ (see [wallet.md](wallet.md#default-wallets) for the templates and bounds). They can be used for address derivation and signing **without registration**. In the serialization, a default wallet has an empty name.
+- **Any other policy** (multisig, miniscript, taproot trees, MuSig2, or even a standard
+ single-key account using a non-standard path) must be **registered** before it can be
+ used.
+
+This guarantees the following security property (except on default accounts):
+- **Strong Account Segregation**: address verification and transaction signing will always
+ inform the user about the involved account.
+
+This is particularly important for accounts involving multiple parties (multisig,
+miniscript, etc).
+
+## Registration and the HMAC
+
+Registration is the step where the user reviews a non-standard policy — its name, the
+script template, and every key — on the trusted screen and approves it once. This protects
+the user from a compromised host silently substituting a malicious policy.
+
+Because the device is stateless, it does not store the approved policy: registration
+instead returns an HMAC that authorizes that exact policy. The host wallet **must persist
+exactly** the wallet policy and its name together with the returned HMAC, and supply them
+on every later call related to the same account (address derivation, signing). See
+[wallet.md](wallet.md#registration-and-usage) for the HMAC mechanics, its seed-derived key,
+the resulting non-revocability, and the *wallet policy id*.
+
+## On-device verification and the trusted screen
+
+The device's security guarantee rests on the **trusted screen**: anything the user
+approves there cannot be forged by a compromised host, because the host has no control
+over what the device displays.
+
+In practice:
+
+- When showing a **receive address** to a user, an integration should derive it with the
+ display option enabled so the user verifies, on the device, that the address belongs to
+ their wallet — a compromised host cannot then swap in an attacker's address. It is also
+ possible to display a **change address**, if desired.
+- The same applies to **public keys / xpubs**: displaying them on-device lets the user
+ confirm them out of band.
+- During **signing**, the device shows the amounts, destinations, and (for registered
+ policies) the wallet account involved. The user is approving what the device displays,
+ not what the host claims. For the user's convenience, *change addresses* are *not* displayed when signing a transaction. The device verifies that they indeed belong to the same account the transaction is spending from.
+
+The client libraries expose this as a `display` (or equivalent) flag on the relevant
+methods.
+
+## Transaction signing model
+
+To sign, the host builds a [PSBT](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki)
+and passes it to the app together with the wallet policy and, for registered wallet accounts, the
+HMAC. The app verifies that it can sign, has the user approve the transaction on the trusted
+screen, and returns the **partial signatures** it is able to produce, keyed by input index.
+
+**Only inputs whose corresponding BIP-32 derivations are present in the PSBT are signed**; if the
+wallet policy has multiple spending paths involving the device for a given input, more than one
+signature may be returned for that input.
+
+The host is responsible for placing the returned signatures into the PSBT, **finalizing** it,
+**extracting** the signed transaction and (possibly) broadcasting it to the network.
+
+### Transactions with Wallet Policies using MuSig2
+
+For policies that use `musig()` key expressions, signing is a two-round protocol: the first round
+produces the *public nonces* (pubnonces), while the second round produces the MuSig2 Partial
+Signatures. More details are described in [musig.md](musig.md).
+
+The app uses the presence of pubnonces in the PSBT to determine which MuSig2 round should be
+performed:
+- if no pubnonces are present in the PSBT, the app executes MuSig2 Round 1, producing and returning
+ the public nonces;
+- if the PSBT contains pubnonces, the app executes the MuSig2 Round 2, and (on success) produces
+ and returns the MuSig2 Partial Signatures.
+
+If the app is only participating in MuSig2 Round 1 and not producing any signature, then user
+confirmation on the trusted screen is not required. With careful coordination from the software
+wallet, this can be used in many cases to provide a seamless MuSig2 signing experience, without
+increasing the user's UX burden.
+
+However, user confirmation is required if, for the same PSBT, the device is able to produce a
+signature (for any spending path), including a MuSig2 Partial Signature (as produced by MuSig2
+Round 2).
+
+It is recommended to *never rely on the signing behavior for PSBTs that contain some pubnonces*,
+but not all: signing is likely to fail in this case, and exact behavior might change in future
+releases.
diff --git a/doc/wallet.md b/doc/wallet.md
index 451f03d..5937ba8 100644
--- a/doc/wallet.md
+++ b/doc/wallet.md
@@ -1,191 +1,106 @@
-# Wallet policy
+# Wallet policies
-A _wallet policy_ is a structured representation of an account secured by a policy expressed with output script descriptors. It is composed by two parts:
-a wallet descriptor template and the vector of key placeholder expressions.
-
-A _wallet descriptor template_ follows language very similar to output descriptor, with a few differences; the biggest one is that each `KEY` expression with a key placeholder `KP` expression, that refers to one of the keys in the _keys information vector_, plus the additional derivation steps to use for that key. Contextually, the keys information vector contains all the relevant _xpubs_, and possibly their key origin information.
+The Ledger Bitcoin app describes every account using a **wallet policy**, the
+representation standardized in
+[BIP-388](https://github.com/bitcoin/bips/blob/master/bip-0388.mediawiki). A wallet policy
+is a pair of:
-Each entry in the key information vector contains an _xpub_ (other types of keys supported in output script descriptors are not allowed), possible preceded by the key origin information. The key origin information is compulsory for internal keys.
-
-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)` (not inside `tr`): k-of-n multisig script using OP_CHECKMULTISIG.
-- `sortedmulti(k,KP_1,KP_2,...,KP_n)` (not inside `tr`): k-of-n multisig script with keys
-sorted lexicographically in the resulting script.
-- `multi_a(k,KP_1,KP_2,...,KP_n)` (only inside `tr`): k-of-n multisig script.
-- `sortedmulti_a(k,KP_1,KP_2,...,KP_n)` (only inside `tr`): k-of-n multisig script with keys
-sorted lexicographically in the resulting script.
-- `tr(KP)` or `tr(KP,TREE)`: P2TR output with the specified key placeholder internal key, and optionally a tree of script paths.
-- any valid [miniscript](https://bitcoin.sipa.be/miniscript) template (only inside top-level `wsh`, or in `TREE`).
+- a **wallet descriptor template** — an output script descriptor in which each key is
+ replaced by a key placeholder (`@0`, `@1`, …); and
+- a **key information vector** — the actual keys (`xpub`s), each optionally preceded by its
+ key origin information.
-`TREE` expressions:
-- any `SCRIPT`expression.
-- An open brace `{`, a `TREE` expression, a comma `,`, a `TREE` expression, and a closing brace `}`.
+The key origin information is compulsory for xpubs controlled by the device. Without it, the xpub
+will be considered external, and the device will not sign for any key derived by it.
-`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 `/<NUM;NUM>/*`, for two distinct decimal numbers
-`NUM` representing unhardened derivations.
+Wallet policies are registered with a short readable *account name* provided by the host wallet, which is shown on-screen.
-The `/**` in the placeholder template represents commonly used paths for
-receive/change addresses, and is equivalent to `<0;1>`.
+For a higher-level explanation of wallet policies, registration, and the security model,
+see [integration.md](integration.md).
-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).
+## Supported scripts
-### Keys information vector
+The following templates are supported as the **top-level** script:
-Each element of the keys origin information vector is a `KEY` expression.
+- `pkh(KP)`, `wpkh(KP)`, `sh(wpkh(KP))` — single-key legacy, native SegWit, and nested
+ SegWit;
+- `sh(multi(...))`, `sh(sortedmulti(...))` — legacy multisig;
+- `sh(wsh(multi(...)))`, `sh(wsh(sortedmulti(...)))` — wrapped-SegWit multisig;
+- `wsh(SCRIPT)` — native SegWit;
+- `tr(KP)` and `tr(KP, TREE)` — taproot, with an optional tree of script paths.
-`KEY` expressions consist of
-- 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))
+Within `wsh(...)`, `SCRIPT` can be `multi(...)`, `sortedmulti(...)`, or a valid SegWit
+[miniscript](https://github.com/bitcoin/bips/blob/master/bip-0379.md) template.
-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).
+Within a taproot `TREE`, each leaf script can be `multi_a(...)`, `sortedmulti_a(...)`, or a
+valid taproot miniscript template.
-A key with no origin information will be treated as external by the hardware wallet.
+Taproot key placeholders (both the taproot internal key, and key expressions used in tapleaves) may
+also be `musig(...)` aggregate-key expressions, as described in [musig.md](musig.md).
-### Additional rules
+## Default wallets
-The wallet policy is invalid if any placeholder expression with additional
-derivation steps is used when the corresponding key information is not an
-xpub.
+A few policies that correspond to standardized single-key accounts can be used for address
+derivation and signing **without prior registration**. For these *default wallet accounts*, the
+wallet name must be empty. They are:
-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.
+| Policy template | Address type | Standard |
+|-------------------|----------------|--------------------------------------------------------------------------------|
+| `pkh(@0/**)` | Legacy | [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) |
+| `sh(wpkh(@0/**))` | Nested SegWit | [BIP-49](https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki) |
+| `wpkh(@0/**)` | Native SegWit | [BIP-84](https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki) |
+| `tr(@0/**)` | Taproot | [BIP-86](https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki) |
-### Implementation-specific restrictions
+A policy is treated as a default wallet only if its single key's origin path follows the
+corresponding BIP. In addition, the BIP-44 `account` level must be at most `100`, and the
+address index at most `50000`. Accounts that exceed those bounds, or use a non-standard
+path, are still usable, but must be registered first.
-- Placeholder _must_ be followed by `/**` or `/<0;1>`.
-- Key expressions only support xpubs at this time (no hex-encoded pubkeys).
-- Very large policies might not be supported because of the device's memory limitations.
+## Serialization
-## Descriptor derivation
+A registered wallet policy comprises:
-From a wallet descriptor template (and the associated vector of keys
-information), one can therefore obtain the 1-dimensional descriptor for
-receive and change addresses by:
+- the **wallet name**, shown to the user on-screen to identify the wallet (empty for a
+ default wallet);
+- the **wallet descriptor template**, as a string;
+- the **key information vector**.
-- 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 `/<M;N>` with `/M` for the receive descriptor, and `/N`
-for the change descriptor.
+It is serialized as the concatenation of:
-For example, the wallet descriptor `pkh(@0/**)` with key information
-`["[d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"]`
-produces the following two descriptors:
+- `1 byte`: `0x02`, the version of the wallet policy language;
+- `1 byte`: the length of the wallet name (`0` for a default wallet);
+- `<variable length>`: the wallet name (empty for default wallets);
+- `<variable length>`: the length of the wallet descriptor template, as a Bitcoin-style
+ variable-length integer;
+- `32 bytes`: the SHA-256 hash of the wallet descriptor template;
+- `<variable length>`: the number of keys in the key information vector, as a Bitcoin-style
+ variable-length integer;
+- `32 bytes`: the root of the canonical Merkle tree of the key information vector.
-- Receive descriptor:
-`pkh([d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*)`
+See [merkle.md](merkle.md) for the Merkle tree construction.
-- Change descriptor:
-`pkh([d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*)`
+The SHA-256 hash of a serialized wallet policy is the **wallet policy id**.
+### Wallet name
-# Policy registration and usage
-The app supports a number of features related to wallet policies. In order to securely sign transactions with a policy wallet (for example in a multisignature), it is necessary to be able to:
+The wallet name must be recognizable by the user when shown on-screen. During
+registration the app enforces:
-- register a wallet, validating all the information (policy and keys involved) with the user on the trusted screen;
-- show the addresses for a registered wallet on the trusted screen;
-- sign spends from the wallet.
+- the name is at least 1 and at most 64 characters long;
+- every character is an ASCII character with code between `0x20` (space) and `0x7e` (`~`),
+ inclusive;
+- the first and last characters are not spaces.
-Since the application is stateless, wallet registration is not persisted on device. In order to make it possible to use a registered wallet in future requests, the device returns a hmac-sha256 (32 bytes long) for the wallet upon a successful registration. The client side is responsible for persisting the wallet policy *and* the returned hmac-sha256, and to provide this information in future requests.
+Registration is rejected for names that do not satisfy these constraints.
-As the symmetric key used for hmac-sha256 is deterministically derived from the hardware wallet seed (using [SLIP-0021](https://github.com/satoshilabs/slips/blob/master/slip-0021.md)), the completed wallet registration is non-revokable.
+## Registration and usage
-## Wallet policy serialization
+Because the app is stateless, a registered policy is not persisted on the device. A
+successful registration instead returns a 32-byte HMAC-SHA256 that authorizes that exact
+policy; the host must store the wallet policy together with this HMAC and supply both on
+every later call that uses the account. The HMAC key is derived deterministically from the
+device seed ([SLIP-0021](https://github.com/satoshilabs/slips/blob/master/slip-0021.md)),
+so registration is non-revocable.
-A registered wallet policy comprises the following:
-- The wallet name, up to 16 bytes long; the name is shown to the user on-screen in order to identify the wallet.
-- The wallet descriptor template as a string.
-- The list of keys.
-
-The wallet policy is serialized as the concatenation of:
-
-- `1 byte`: a byte equal to `0x02`, the version of the wallet policy language
-- `1 byte`: the length of the wallet name (0 for standard wallet)
-- `<variable length>`: the wallet name (empty for standard wallets)
-- `<variable length>`: the length of the wallet descriptor template, encoded as a Bitcoin-style variable-length integer
-- `32 bytes`: the sha256 hash of the wallet descriptor template
-- `<variable length>`: the number of keys in the list of keys, encoded as a Bitcoin-style variable-length integer
-- `<32 bytes>`: the root of the canonical Merkle tree of the list of keys
-
-See [merkle](merkle.md) for information on Merkle trees.
-
-The sha256 hash of a serialized wallet policy is used as a *wallet policy id*.
-
-## Wallet name
-
-The wallet name must be recognizable from the user when shown on-screen. Currently, the following limitations apply during wallet registration:
-- The wallet name must be at least 1 and at most 64 characters long.
-- Each character must be an ASCII character with code at least 32 = 0x20 (the 'space' character) and at most 125 = 0x7e (the '~' character).
-- The first and the last character must _not_ be spaces.
-
-The hardware wallet will reject registration for wallet names not respecting the above constraints.
-
-## Supported policies
-
-The following policy types are currently supported as top-level scripts:
-
-- `sh(multi(...))` and `sh(sortedmulti(...))` (legacy multisignature wallets);
-- `sh(wsh(multi(...)))` and `sh(wsh(sortedmulti(...)))` (wrapped-segwit multisignature wallets);
-- `wsh(SCRIPT)`;
-- `tr(KP)` and `tr(KP,TREE)`.
-
-`SCRIPT` expression within `wsh` can be:
-- `multi` or `sortedmulti`;
-- a valid SegWit miniscript template.
-
-`SCRIPT` expression within `TREE` can be:
-- `multi_a` or `sortedmulti_a`;
-- a valid taproot miniscript template.
-
-# Default wallets
-A few policies that correspond to standardized single-key wallets can be used without requiring any registration; in the serialization, the wallet name must be a zero-length string. Those are the following policies:
-
-- ``pkh(@0/**)`` - legacy addresses as per [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)
-- ``wpkh(@0/**)`` - native segwit addresses per [BIP-84](https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki)
-- ``sh(wpkh(@0/**))`` - nested segwit addresses as per [BIP-49](https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki)
-- ``tr(@0/**)`` - single Key P2TR as per [BIP-86](https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki)
-
-Note that the wallet policy is considered standard (and therefore usable for signing without prior registration) only if the signing paths (defined in the key origin information) adhere to the corresponding BIP. Moreover, the BIP-44 `account` level must be at most `100`, and the `address index` at most `50000`. Larger values can still be used by registering the policy.
+The registration, address-derivation, and signing flows are described in
+[integration.md](integration.md) (concepts) and [bitcoin.md](bitcoin.md) (wire protocol).
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.