-
Notifications
You must be signed in to change notification settings - Fork 21
Add ELIP for AMP2 descriptors #43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
LeoComandini
wants to merge
1
commit into
ElementsProject:main
Choose a base branch
from
LeoComandini:amp2
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+172
−0
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,172 @@ | ||||||
| <pre> | ||||||
| ELIP: XXX | ||||||
| Layer: Wallet | ||||||
| Title: AMP2 Descriptors | ||||||
| Author: Leonardo Comandini <leonardo@blockstream.com> | ||||||
| Comments-Summary: No comments yet. | ||||||
| Comments-URI: https://github.com/ElementsProject/elips/wiki/Comments:ELIP-0XXX | ||||||
| Status: Draft | ||||||
| Type: Standards Track | ||||||
| Created: 2026-07-28 | ||||||
| License: BSD-3-Clause | ||||||
| </pre> | ||||||
|
|
||||||
| ==Introduction== | ||||||
|
|
||||||
| ===Abstract=== | ||||||
|
|
||||||
| This document proposes a standard way to derive AMP2 descriptors. | ||||||
|
|
||||||
| ===Copyright=== | ||||||
|
|
||||||
| This document is licensed under the 3-clause BSD license. | ||||||
|
|
||||||
| ===Motivation=== | ||||||
|
|
||||||
| AMP2 is a service that enforces transfer authorization by cosigning Elements transactions: users create wallets where both their own signature(s) and the AMP2 server's signature(s) are necessary to spend. This cosigning arrangement is expressed as a descriptor combining key material controlled by the user with key material controlled by the AMP2 server. | ||||||
|
|
||||||
| A naive approach would let each wallet implementation choose its own derivation paths and script structure for combining the user's and the AMP2 server's keys. | ||||||
| However, a wallet is ultimately recovered from its master secret, and an ad-hoc, implementation-specific construction would tie a user's funds to the wallet software that originally created them. | ||||||
| Users would be unable to independently verify that their wallet was set up correctly, nor recover it, or migrate to another wallet, without relying on that specific implementation. | ||||||
|
|
||||||
| This ELIP defines a standard way to derive AMP2 descriptors that: | ||||||
| * Combines the user's key material with the AMP2 server's key material in a well-defined script structure | ||||||
| * Is derived deterministically from the user's master secret and the AMP2 server's public information | ||||||
| * Enables interoperability between wallet software implementing the AMP2 protocol, including recovery from the user's master secret and the AMP2 server's master extended public key | ||||||
|
|
||||||
| ==Design== | ||||||
|
|
||||||
| ===Specification=== | ||||||
|
|
||||||
| An AMP2 [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki CT Descriptor] has multiple components: | ||||||
| * The overall script structure combining the user's and the server's keys | ||||||
| * The user's extended public key, <code>USER_XPUB</code> | ||||||
| * The AMP2 server's extended public key, <code>SERVER_XPUB</code> | ||||||
| * The descriptor blinding key, <code>VIEW</code> | ||||||
|
|
||||||
| The following sections detail how to derive them and explain their rationale. | ||||||
|
|
||||||
| ====Descriptor Structure==== | ||||||
|
|
||||||
| AMP2 descriptors use a <code>P2WSH</code> 2-of-2 multisig script: | ||||||
| <pre> | ||||||
| ct(VIEW,elwsh(multi(2,SERVER_XPUB/<0;1>/*,USER_XPUB/<0;1>/*))) | ||||||
| </pre> | ||||||
|
|
||||||
| The script requires two signatures out of the two keys <code>SERVER_XPUB</code> and <code>USER_XPUB</code>, so that neither the user nor the AMP2 server can unilaterally move funds: every spend must be cosigned by the AMP2 server, which enforces the transfer authorization policy, and by the user, who retains custody of their own key. | ||||||
|
|
||||||
| A plain, segwit v0 <code>multi</code> expression was chosen over alternatives such as <code>tr</code>/MuSig2, <code>sh-multi</code> or bare multisig because it is a long-established, widely deployed construction: it does not require an interactive key-aggregation or signing protocol between the user and the server, and it is broadly supported by wallet software, HW signers, and HSMs already in production use. This makes it straightforward for existing signing devices to participate in AMP2 wallets without additional development. | ||||||
|
|
||||||
| <code>USER_XPUB</code> and <code>SERVER_XPUB</code> are followed by two extra derivation steps for change and address index: <code>/<0;1>/*</code>. | ||||||
|
|
||||||
| Derivation of <code>USER_XPUB</code>, <code>SERVER_XPUB</code> and <code>VIEW</code> is defined in the sections below. | ||||||
|
|
||||||
| ====User Xpub==== | ||||||
|
|
||||||
| <code>USER_XPUB</code> is derived from the user master key using <code>USER_PATH</code>, a [https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP44] BIP44 derivation path: | ||||||
| <pre> | ||||||
| USER_PATH = m/purpose'/coin_type'/account' | ||||||
| </pre> | ||||||
| Where <code>purpose</code> is <code>1095585842</code> (hex <code>0x414d5032</code>, bytes <code>b'AMP2'</code>). | ||||||
|
|
||||||
| <code>coin_type</code> follows [https://github.com/satoshilabs/slips/blob/master/slip-0044.md SLIP-44], and is <code>1776</code> on Liquid mainnet, and <code>1</code> on Liquid Testnet and Liquid Regtest. | ||||||
|
|
||||||
| The <code>account</code> field makes it possible to derive multiple AMP2 accounts from the same master secret. | ||||||
|
|
||||||
| [https://github.com/bitcoin/bips/blob/master/bip-0087.mediawiki BIP87] is not used, as its purpose field is not specific to AMP2 and could be used for other multisig setups. | ||||||
|
|
||||||
| ====Server Xpub==== | ||||||
|
|
||||||
| <code>SERVER_XPUB</code> is derived from the AMP2 server's master extended public key via <code>SERVER_PATH</code>, a user-specific, unhardened derivation path. | ||||||
| <code>SERVER_PATH</code> is derived as follows: | ||||||
| * Derive <code>USER_XPUB</code> as defined in the previous section, and obtain the corresponding public key, serialized in compressed form (33 bytes) | ||||||
| * Compute the SHA256 hash of the public key bytes | ||||||
| * Take the first 12 bytes of the hash | ||||||
| * Split them into 3 chunks of 4 bytes each | ||||||
| * For each chunk, clear the most significant bit (mask with <code>0x7FFFFFFF</code>)<ref>Necessary to keep each value below 2**31, and thus a valid unhardened index.</ref>, and convert the result to an integer using big-endian byte order (most significant byte first) | ||||||
| * Construct <code>SERVER_PATH</code> from the three integers obtained, preserving their order | ||||||
|
|
||||||
| A user-specific <code>SERVER_XPUB</code> avoids reusing the same server ''public key'' across multiple users. Key reuse would allow blockchain observers to link transactions across users, resulting in a loss of privacy.<ref>This mechanism provides 93 bits of entropy, and is similar to, and inspired by, the GreenAddress/Blockstream Green/Multisig Shield "gait_path" mechanism, used in multisig accounts including AMP0 accounts.</ref> | ||||||
|
|
||||||
| ====Descriptor Blinding Key==== | ||||||
|
|
||||||
| The descriptor blinding key <code>VIEW</code> is a '''view key''' as specified in [https://github.com/ElementsProject/ELIPs/blob/main/elip-0150.mediawiki ELIP-150], derived as follows: | ||||||
| * Get the server xpub fingerprint, <code>server_fingerprint</code> | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A careless reader (like my clanker) might use the fingerprint of Maybe a small clarification here, or otherwise add another specifier like
Suggested change
|
||||||
| * Clear the most significant bit of <code>server_fingerprint</code> (mask with <code>0x7FFFFFFF</code>), and convert the result to an integer using big-endian byte order (most significant byte first), <code>server_fingerprint_masked</code> | ||||||
| * Derive the user master extended key using <code>VIEW_PATH = m/purpose'/coin_type'/account'/server_fingerprint_masked'</code>, where the first 3 derivation steps are the same as those used for <code>USER_PATH</code>, and the last one is obtained at the step above | ||||||
| * Get the public key from the obtained xpub, serialized in compressed form (33 bytes) | ||||||
| * Compute <code>VIEW</code> as the hex-encoded SHA256 hash of the public key bytes | ||||||
|
|
||||||
| [https://github.com/satoshilabs/slips/blob/master/slip-0077.md SLIP-77] is not used, as that descriptor blinding key would be shared with singlesig wallets. | ||||||
|
|
||||||
| [https://github.com/ElementsProject/ELIPs/blob/main/elip-0151.mediawiki ELIP-151] is not used either, as it derives <code>VIEW</code> from the ordinary (unblinded) descriptor itself: anyone who learns that descriptor, without ever seeing <code>VIEW</code>, can then derive it and unblind the wallet's outputs. This is problematic when the ordinary descriptor is shared with a party that is not meant to unblind the wallet, such as a [https://github.com/RCasatta/waterfalls Waterfalls] server, which needs it to efficiently scan for the wallet's transactions. | ||||||
|
|
||||||
| This derivation is compatible with HW signers, since they don't need it to export any secret, just another xpub. | ||||||
|
|
||||||
| For the same user, AMP2 descriptors involving different servers use different descriptor blinding keys, since <code>VIEW_PATH</code> depends on <code>server_fingerprint</code>.<ref>A malicious AMP2 server could grind its key to match the fingerprint of an existing AMP2 server, and thereby obtain the same descriptor blinding key as that server. In practice this attack is not a concern, since AMP2 servers are few and operate under a known reputation.</ref> | ||||||
|
|
||||||
| ==Test Vectors== | ||||||
|
|
||||||
| The following user mnemonics, account and AMP2 server xpub yield the given CT descriptors and [https://github.com/ElementsProject/ELIPs/blob/main/elip-0152.mediawiki DWIDs] on the specified networks: | ||||||
|
|
||||||
| * Test Vector 1 | ||||||
| ** Description: Liquid | ||||||
| ** Network: Liquid | ||||||
| ** User Mnemonic: <code>abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about</code> | ||||||
| ** AMP2 Server Xpub: <code>xpub661MyMwAqRbcGYK6ARxU2GyrYN259h9aaesSRk8TnhgHx54RCAXbcnsvqVPbTcfcR96ucYohYYsu7j3GrowCcrtQ7EjoUDPGjmj4apw3wCk</code> | ||||||
| ** User Account: 0 | ||||||
| ** CT Descriptor: <code>ct(a4c4444eae48b72232e3ce3fa8f7e4d75d9da5a4257e908a4ba5adfa7e982bfa,elwsh(multi(2,[28645006/1566545016/81752770/1667703741]xpub6CYNWCA4dpHmy8Kn41tJYysdondHULHQ4WkXj4Af7BbfxyDTV4ayx27KFaSz6o9DLpH6PjQxHCkTspjx8rSHmvmWTqDi3ieXjkd3aFYVUGD/<0;1>/*,[73c5da0a/1095585842'/1776'/0']xpub6DL1t5jE2fzoywD4o3WDjCrjyH74C6mAESxhKXh3inmpdoE2jVwxBJcNaf3v7f5XtKcu6SYiBNjSbXPLsBThvp1RA1CECP1v42qvwuJUQyX/<0;1>/*)))#nz0yy2ml</code> | ||||||
| ** DWID: <code>4b2f-fca3-1d2e-0a8b-0d58-3ef5-9375-12cd</code> | ||||||
|
|
||||||
| * Test Vector 2 | ||||||
| ** Description: Testnet | ||||||
| ** Network: Liquid Testnet | ||||||
| ** User Mnemonic: <code>abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about</code> | ||||||
| ** AMP2 Server Xpub: <code>tpubD6NzVbkrYhZ4YLVwccwZECKDsV7j95ee8HTjnJBc8cSBhMj8GPNgmEYm5XUNz7crD3dpE8Ka5ehwouXtFfnSWJLhAqV79k3WKjKULsSTp2C</code> | ||||||
| ** User Account: 0 | ||||||
| ** CT Descriptor: <code>ct(e3e3cc5de0e37a0f65b0cb170dcab67ed508a1e76e5b3f0e2aa143b86bc5000b,elwsh(multi(2,[28645006/2088330946/1132574986/2019598932]tpubDCPYh8t4rbkhpDXeVLUdGnjoSLXheJgxyAxj2NGokPTQ89KbKHpa3qZrE8n1i4J1eVMzY2qLqsQoXcxjHHk1qDajRpWhxiud2fbsEVSmsWQ/<0;1>/*,[73c5da0a/1095585842'/1'/0']tpubDDKAX9d8KBy2HJ5UTMg4xydwC7Jssy9qfnKrs5LTpM8PpBAiwqZ7k2GVA2P5kiWCPjnmHbDMxBng8FzDBHVqHpQkAwwc4VzXtGx1AY7zc9C/<0;1>/*)))#k7sxgkyp</code> | ||||||
| ** DWID: <code>ded1-9ff5-4291-6309-3c91-a4d8-cfe5-8f74</code> | ||||||
|
|
||||||
| * Test Vector 3 | ||||||
| ** Description: Regtest | ||||||
| ** Network: Liquid Regtest | ||||||
| ** User Mnemonic: <code>abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about</code> | ||||||
| ** AMP2 Server Xpub: <code>tpubD6NzVbkrYhZ4YLVwccwZECKDsV7j95ee8HTjnJBc8cSBhMj8GPNgmEYm5XUNz7crD3dpE8Ka5ehwouXtFfnSWJLhAqV79k3WKjKULsSTp2C</code> | ||||||
| ** User Account: 0 | ||||||
| ** CT Descriptor: <code>ct(e3e3cc5de0e37a0f65b0cb170dcab67ed508a1e76e5b3f0e2aa143b86bc5000b,elwsh(multi(2,[28645006/2088330946/1132574986/2019598932]tpubDCPYh8t4rbkhpDXeVLUdGnjoSLXheJgxyAxj2NGokPTQ89KbKHpa3qZrE8n1i4J1eVMzY2qLqsQoXcxjHHk1qDajRpWhxiud2fbsEVSmsWQ/<0;1>/*,[73c5da0a/1095585842'/1'/0']tpubDDKAX9d8KBy2HJ5UTMg4xydwC7Jssy9qfnKrs5LTpM8PpBAiwqZ7k2GVA2P5kiWCPjnmHbDMxBng8FzDBHVqHpQkAwwc4VzXtGx1AY7zc9C/<0;1>/*)))#k7sxgkyp</code> | ||||||
| ** DWID: <code>a73a-c707-978f-cb7c-8912-5868-34c9-ee12</code> | ||||||
|
|
||||||
| * Test Vector 4 | ||||||
| ** Description: Liquid, different account | ||||||
| ** Network: Liquid | ||||||
| ** User Mnemonic: <code>abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about</code> | ||||||
| ** AMP2 Server Xpub: <code>xpub661MyMwAqRbcGYK6ARxU2GyrYN259h9aaesSRk8TnhgHx54RCAXbcnsvqVPbTcfcR96ucYohYYsu7j3GrowCcrtQ7EjoUDPGjmj4apw3wCk</code> | ||||||
| ** User Account: 1 | ||||||
| ** CT Descriptor: <code>ct(bb2c64d4f5d6d0f467848ea5679d7a06645214c2787440fd45312dbbdd0025c6,elwsh(multi(2,[28645006/613433853/1622795276/321357256]xpub6D7HYys28KEsfohLCGoJT7zpEW4adABiuacczzyDdtoQR95rtc2RXBoH4sgCaxkkzTB69eDhEBiLoev5VYx77jdaZjJueZ1xrm9NSbhspaR/<0;1>/*,[73c5da0a/1095585842'/1776'/1']xpub6DL1t5jE2fzozbCH1A1VxeexbVzYwMARaLDhq8FREmLkDWyu5HnpDrTzVzYBLBnso4G4chhTYZZyGnGrLcR2wg7qPVTdLns5nZ9KgwbQ9iT/<0;1>/*)))#5s600znn</code> | ||||||
| ** DWID: <code>5c5b-05fd-0fe1-58ef-b6a5-c54f-3e56-e478</code> | ||||||
|
|
||||||
| * Test Vector 5 | ||||||
| ** Description: Liquid, different user | ||||||
| ** Network: Liquid | ||||||
| ** User Mnemonic: <code>legal winner thank year wave sausage worth useful legal winner thank yellow</code> | ||||||
| ** AMP2 Server Xpub: <code>xpub661MyMwAqRbcGYK6ARxU2GyrYN259h9aaesSRk8TnhgHx54RCAXbcnsvqVPbTcfcR96ucYohYYsu7j3GrowCcrtQ7EjoUDPGjmj4apw3wCk</code> | ||||||
| ** User Account: 0 | ||||||
| ** CT Descriptor: <code>ct(4178602d5bd9ad236431aaeea92086c33e326496676b5ef458a5628a40afccf3,elwsh(multi(2,[28645006/1075424887/1038076759/2134735410]xpub6Bu9CyVCvQNHYChzDLGa2QrH3XAYg7xvRYhReTX7b5NvkKyu3MHxnKmBExMyd9TtP3aqtg5t1aCVv17znqaeRjhL1HGK34zYAYf1GJvRTkK/<0;1>/*,[b8688df1/1095585842'/1776'/0']xpub6CGoCXyd13GGVqRamaWQcW6GtCKezevWscBZbuaWvHjXXRjGhzDpcsBPVs19cpz6tiEsdadMgHH8m9CUPQr4unwtPyLeC9S545Dt6eN2pwd/<0;1>/*)))#j6yfhcnk</code> | ||||||
| ** DWID: <code>0328-ea41-7816-2f18-e86d-f110-bec4-f4eb</code> | ||||||
|
|
||||||
| * Test Vector 6 | ||||||
| ** Description: Liquid, different server | ||||||
| ** Network: Liquid | ||||||
| ** User Mnemonic: <code>abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about</code> | ||||||
| ** AMP2 Server Xpub: <code>xpub661MyMwAqRbcEsjq2muW5PYkDikFgHuWJGzu1WrZiQgHUsgEeKMtGducsZe1iRsGAGNGDzmWYDM69ya24LMyR7mDhtzqQsc286XEQfM2kkV</code> | ||||||
| ** User Account: 0 | ||||||
| ** CT Descriptor: <code>ct(72e022e013e18c7eacc659d591b73df99ec749f9ebcf0b7690153d0538f4f5e0,elwsh(multi(2,[3f635a63/1566545016/81752770/1667703741]xpub6DTwkNfd3EDJmyidC6zGYdAGHoMyh13qNRQJKSDzNVPF4LMf7kcULKQ8DuTD6SRovsSJSFcgB3zHFeE1mbe4a548VK8VbabiYZGssURqwx7/<0;1>/*,[73c5da0a/1095585842'/1776'/0']xpub6DL1t5jE2fzoywD4o3WDjCrjyH74C6mAESxhKXh3inmpdoE2jVwxBJcNaf3v7f5XtKcu6SYiBNjSbXPLsBThvp1RA1CECP1v42qvwuJUQyX/<0;1>/*)))#p57xtc0q</code> | ||||||
| ** DWID: <code>7e5d-8182-ec4f-cf90-7be8-20f5-b3d8-8694</code> | ||||||
|
|
||||||
| ==Reference Implementation== | ||||||
|
|
||||||
| Implemented in LWK: https://github.com/blockstream/lwk | ||||||
|
|
||||||
| ==Footnotes== | ||||||
|
|
||||||
| <references /> | ||||||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: duplicate "BIP44"