Skip to content

Commit b63ce04

Browse files
authored
Merge pull request #1074 from zcash/p2sh-multisig
[ZIP 48] P2SH multisig
2 parents 4cf2b44 + 98dd463 commit b63ce04

File tree

3 files changed

+274
-5
lines changed

3 files changed

+274
-5
lines changed

README.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ Released ZIPs
101101
<tr> <th>ZIP</th> <th>Title</th> <th>Status</th> </tr>
102102
<tr> <td>0</td> <td class="left"><a href="zips/zip-0000.rst">ZIP Process</a></td> <td>Active</td>
103103
<tr> <td>32</td> <td class="left"><a href="zips/zip-0032.rst">Shielded Hierarchical Deterministic Wallets</a></td> <td>Final</td>
104-
<tr> <td>48</td> <td class="left"><a href="zips/zip-0048.md">Multi-Script Hierarchy for Transparent Multisig Wallets</a></td> <td></td>
105104
<tr> <td>129</td> <td class="left"><a href="zips/zip-0129.md">Zcash Transparent Multisig Setup</a></td> <td></td>
106105
<tr> <td>143</td> <td class="left"><a href="zips/zip-0143.rst">Transaction Signature Validation for Overwinter</a></td> <td>Final</td>
107106
<tr> <td>155</td> <td class="left"><a href="zips/zip-0155.rst">addrv2 message</a></td> <td>Proposed</td>
@@ -163,6 +162,7 @@ written.
163162
<tr> <th>ZIP</th> <th>Title</th> <th>Status</th> </tr>
164163
<tr> <td><span class="reserved">1</span></td> <td class="left"><a class="reserved" href="zips/zip-0001.rst">Network Upgrade Policy and Scheduling</a></td> <td>Reserved</td>
165164
<tr> <td><span class="reserved">2</span></td> <td class="left"><a class="reserved" href="zips/zip-0002.rst">Design Considerations for Network Upgrades</a></td> <td>Reserved</td>
165+
<tr> <td>48</td> <td class="left"><a href="zips/zip-0048.md">Transparent Multisig Wallets</a></td> <td>Draft</td>
166166
<tr> <td>68</td> <td class="left"><a href="zips/zip-0068.rst">Relative lock-time using consensus-enforced sequence numbers</a></td> <td>Draft</td>
167167
<tr> <td><span class="reserved">76</span></td> <td class="left"><a class="reserved" href="zips/zip-0076.rst">Transaction Signature Validation before Overwinter</a></td> <td>Reserved</td>
168168
<tr> <td>112</td> <td class="left"><a href="zips/zip-0112.rst">CHECKSEQUENCEVERIFY</a></td> <td>Draft</td>
@@ -271,7 +271,7 @@ Index of ZIPs
271271
<tr> <td><span class="reserved">1</span></td> <td class="left"><a class="reserved" href="zips/zip-0001.rst">Network Upgrade Policy and Scheduling</a></td> <td>Reserved</td>
272272
<tr> <td><span class="reserved">2</span></td> <td class="left"><a class="reserved" href="zips/zip-0002.rst">Design Considerations for Network Upgrades</a></td> <td>Reserved</td>
273273
<tr> <td>32</td> <td class="left"><a href="zips/zip-0032.rst">Shielded Hierarchical Deterministic Wallets</a></td> <td>Final</td>
274-
<tr> <td>48</td> <td class="left"><a href="zips/zip-0048.md">Multi-Script Hierarchy for Transparent Multisig Wallets</a></td> <td></td>
274+
<tr> <td>48</td> <td class="left"><a href="zips/zip-0048.md">Transparent Multisig Wallets</a></td> <td>Draft</td>
275275
<tr> <td>68</td> <td class="left"><a href="zips/zip-0068.rst">Relative lock-time using consensus-enforced sequence numbers</a></td> <td>Draft</td>
276276
<tr> <td><span class="reserved">76</span></td> <td class="left"><a class="reserved" href="zips/zip-0076.rst">Transaction Signature Validation before Overwinter</a></td> <td>Reserved</td>
277277
<tr> <td>112</td> <td class="left"><a href="zips/zip-0112.rst">CHECKSEQUENCEVERIFY</a></td> <td>Draft</td>

zips/zip-0048.md

Lines changed: 270 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,278 @@
11

22
ZIP: 48
3-
Title: Multi-Script Hierarchy for Transparent Multisig Wallets
3+
Title: Transparent Multisig Wallets
44
Owners: Kris Nuttycombe <[email protected]>
55
Jack Grigg <[email protected]>
6+
Daira-Emma Hopwood <[email protected]>
67
78
Credits: Fontaine
9+
Status: Draft
810
Category: Wallet
11+
Created: 2025-08-25
12+
License: MIT
913
Discussions-To: <https://github.com/zcash/zips/issues/1059>
14+
15+
16+
# Terminology
17+
18+
The key words "MUST", "REQUIRED", "MUST NOT", "SHOULD", and "MAY" in this
19+
document are to be interpreted as described in BCP 14 [^BCP14] when, and
20+
only when, they appear in all capitals.
21+
22+
The terms "Mainnet" and "Testnet" in this document are to be interpreted as
23+
defined in the Zcash protocol specification [^protocol-networks].
24+
25+
26+
# Abstract
27+
28+
This ZIP defines how wallets should implement transparent multisignature addresses in the
29+
Zcash ecosystem. It specifies how to derive the necessary key material in a deterministic
30+
way, and how to create transactions spending transparent multisig-controlled funds.
31+
32+
Any future changes, or new transparent protocols or scripts, will be made as Revisions to
33+
this ZIP.
34+
35+
36+
# Motivation
37+
38+
There are a variety of important use cases for funds being controlled by a quorum of
39+
signers. In Bitcoin, these use cases were served via "P2SH multisig", or more specifically
40+
a Pay-to-Multi-Signature (P2MS) script specified by a P2SH address.
41+
42+
A P2SM script can be constructed from any set of secp256k1 public keys, and anyone can use
43+
any mechanism for obtaining or storing the corresponding signing keys by private agreement.
44+
However, in order to ensure that funds are easily recoverable from backups, several
45+
different BIPs emerged for P2MS scripts using BIP 32 Hierarchical Derivation [^bip-0032].
46+
Each of these has some problem when attempting to apply it as-written to Zcash:
47+
48+
- BIP 45 [^bip-0045] uses `m / purpose' / cosigner_index / change / address_index`.
49+
- The problem is that unlike BIP 44, this BIP does not include `coin_type' / account'`
50+
in its derivation path. If naively applied to Zcash, it would result in key reuse
51+
between Bitcoin and Zcash, which creates the potential for cross-protocol attacks
52+
that would be complex to rule out.
53+
- This is the BIP that essentially all hardware wallets use for Bitcoin P2SH multisig.
54+
55+
- BIP 48 [^bip-0048] uses `m / purpose' / coin_type' / account' / script_type' / change / address_index`
56+
- The problem is that `script_type` is specified solely for Bitcoin's Native Segwit (P2WSH)
57+
and Nested Segwit (P2SH-P2WSH). Several conflicting proposed `script_type` constants
58+
for P2SH have been considered at various points, and were rejected due to P2SH being
59+
considered "legacy" in the context of Bitcoin.
60+
- This is the BIP that essentially all hardware wallets use for P2WSH and P2SH-P2WSH on
61+
any Bitcoin-compatible chain.
62+
63+
- BIP 87 [^bip-0087] uses `m / purpose' / coin_type' / account' / change / address_index`
64+
- The problem is that this BIP does not consider key reuse across different scripts
65+
(which are to some degree different payment protocols) to be an issue, whereas we do.
66+
- This BIP is essentially unused by hardware wallets (which instead implement BIPs 45
67+
and 48).
68+
69+
While there is verifiable usage of P2SH multisig on the Zcash chain, there has been no
70+
standard approach for public deployments (likely due to the above issues), and thus no
71+
support for it in Zcash-compatible hardware wallets. This ZIP fills the gap.
72+
73+
74+
# Privacy Implications
75+
76+
This does not have any privacy implications beyond what users already accept by
77+
using the transparent protocol and BIP 44 in particular for transparent address
78+
derivation.
79+
80+
81+
# Requirements
82+
83+
Hardware wallet providers should only need to make limited changes relative to how they
84+
support Bitcoin P2SH multisig. As such, this specification should hew closely to the
85+
specifications used in the Bitcoin ecosystem for P2SH support.
86+
87+
88+
# Specification
89+
90+
This ZIP applies to both Mainnet and Testnet, using the same $\mathit{coin\_type}$
91+
constants as defined in [^slip-0044] where applicable. Note that in keeping with that
92+
document, all cryptocurrency testnets share $\mathit{coin\_type}$ index 1.
93+
94+
## Output descriptor and script
95+
96+
Zcash wallets SHOULD use the BIP 383 [^bip-0383] `sortedmulti()` script expression to
97+
produce Zcash P2MS scripts, which would then be contained in the BIP 381 [^bip-0381]
98+
`sh()` script expression to produce Zcash P2SH addresses.
99+
100+
The following BIP 388 [^bip-0388] wallet descriptor template produces a 2-of-3 P2SH
101+
multisig wallet compatible with this ZIP:
102+
103+
```
104+
sh(sortedmulti(2,@0/**,@1/**,@2/**))
105+
```
106+
107+
## Hierarchical Derivation
108+
109+
Given a set of participants that each have some seed material (e.g. BIP 39 [^bip-0039]
110+
mnemonic phrases), and a BIP 380 [^bip-0380] output descriptor that encodes the desired
111+
multisig policy, wallets need to produce their individual contributions to the BIP 388
112+
key information vector [^bip-0388-key-information-vector]. This specification adopts
113+
BIP 48 [^bip-0048] for this purpose, with the following modification:
114+
115+
- The $\mathit{script\_type}$ values for Native Segwit and Nested Segwit MUST NOT be used
116+
in a Zcash context.
117+
118+
- The following Zcash-specific $\mathit{script\_type}$ key spaces are defined:
119+
120+
- A path component of $133000'$ represents “Zcash P2SH”.
121+
122+
## Transaction construction
123+
124+
The transaction construction workflow for a P2SH multisig wallet is as follows:
125+
126+
- One of the participants uses their local wallet to construct a PCZT [^zip-pczt] that
127+
spends transparent UTXOs controlled by the multisig wallet, with the desired outputs,
128+
and a change output to a P2SH address derived at the path
129+
`m/48'/coin_type'/account'/133000'/1/*`.
130+
131+
- The PCZT is conveyed to the other wallet participants out-of-band (via a private and
132+
authenticated channel, such as a group end-to-end-encrypted messenger).
133+
134+
- Each participant's wallet MUST verify that the PCZT's change outputs are to an address
135+
that the multisig wallet controls.
136+
137+
- Each participant verifies that the PCZT performs the spend action that they expect.
138+
139+
- Each participant modifies their copy of the PCZT to include their signature(s) using
140+
their wallet.
141+
142+
- Each participant conveys their signed PCZT to one (or more) of the other wallet
143+
participants (likely via the same channel that the unsigned PCZT was received on).
144+
145+
- One participant takes a threshold of signed PCZTs, combines them, and extracts the final
146+
transaction for broadcasting to the network.
147+
148+
Wallets SHOULD ensure they are fully synced before proposing a transaction that generates
149+
transparent change, to minimize the likelihood of reusing a P2SH change address.
150+
151+
152+
# Examples
153+
154+
## 2-of-3 P2SH multisig on Zcash mainnet
155+
156+
Let the seeds for the three participants be (in hex):
157+
158+
```
159+
[
160+
"0101010101010101010101010101010101010101010101010101010101010101",
161+
"0202020202020202020202020202020202020202020202020202020202020202",
162+
"0303030303030303030303030303030303030303030303030303030303030303"
163+
]
164+
```
165+
166+
TODO: Update example below with actual key fingerprints and xpub encodings.
167+
168+
The wallet descriptor template for this multisig is:
169+
170+
```
171+
sh(sortedmulti(2,@0/**,@1/**,@2/**))
172+
```
173+
174+
The three parties each derive their transparent extended public key from their respective
175+
wallet seed, using the path `m/48'/133'/0'/133000'`. The parties then combine their
176+
respective keys to produce a key information vector [^bip-0388-key-information-vector]:
177+
178+
```
179+
[
180+
"[MSTKFP_0/48'/133'/0'/133000']EXTENDED_PUBLIC_KEY_0",
181+
"[MSTKFP_1/48'/133'/0'/133000']EXTENDED_PUBLIC_KEY_1",
182+
"[MSTKFP_2/48'/133'/0'/133000']EXTENDED_PUBLIC_KEY_2"
183+
]
184+
```
185+
186+
The wallet policy is the composition of the wallet descriptor template and the key
187+
information vector. The corresponding multipath descriptor [^bip-0389] derived from this
188+
policy [^bip-0388-descriptor-derivation] is (newlines and whitespace added for legibility):
189+
190+
```
191+
sh(
192+
sortedmulti(
193+
2,
194+
[MSTKFP_0/48'/133'/0'/133000']EXTENDED_PUBLIC_KEY_0/<0;1>/*,
195+
[MSTKFP_1/48'/133'/0'/133000']EXTENDED_PUBLIC_KEY_1/<0;1>/*,
196+
[MSTKFP_2/48'/133'/0'/133000']EXTENDED_PUBLIC_KEY_2/<0;1>/*
197+
)
198+
)
199+
```
200+
201+
# Rationale
202+
203+
The choice to use BIP 48 means that participants are not restricted to constructing a
204+
single P2SH address; once a wallet has obtained the completed wallet policy, it can
205+
(without additional coordination) produce the same deterministic sequence of P2SH
206+
addresses as every other participant.
207+
208+
We specify a likely-non-colliding $\mathit{script\_type}$ instead of using a path
209+
component of either $0'$ (the gap left in BIP 48) or $2'$ (the next unassigned constant in
210+
BIP 48), because both of those values have in the past been proposed and rejected as
211+
referring to P2SH. This means that there is no compatibility benefit to trying to use one
212+
or the other, and the likelihood of a collision with some other use case is higher.
213+
Instead we pick a value that is prefixed (in decimal) with the SLIP 44 [^slip-0044]
214+
$\mathit{coin\_type}$ for Zcash mainnet, which is highly unlikely to organically occur in
215+
another related specification.
216+
217+
By not using BIP 45, Zcash addresses will not be compatible with BIP 45 P2SH derivation
218+
paths. We consider this acceptable because we explicitly do not want users that use the
219+
same mnemonic phrase for both Bitcoin and Zcash to produce addresses that reuse the same
220+
public keys.
221+
222+
By not using BIP 45 (with a $\mathit{cosigner\_index}$ path element), all cosigners produce
223+
the same sequence of P2SH addresses. This is good for agreement on, for example, the ZIP 1016 [^zip-1016]
224+
Key-Holder Organizations’ Mainnet address, but in general usage means that two cosigners
225+
proposing transactions can race and use the same P2SH address twice. This could result in a
226+
situation where different members of the signing set inadvertently give the same P2SH
227+
address to different counterparties, linking the associated payment
228+
activity. We consider this tradeoff acceptable because it aligns with what hardware
229+
wallets have done for years (implying that users are fine with the usability). We consider
230+
the risk acceptable because avoiding linkage between transparent addresses is hard in any
231+
case, and not something that Zcash actively attempts to avoid (the shielded protocols are
232+
designed for this use case).
233+
234+
235+
# Reference implementation
236+
237+
TBD
238+
239+
240+
# References
241+
242+
[^BCP14]: [Information on BCP 14 — "RFC 2119: Key words for use in RFCs to Indicate Requirement Levels" and "RFC 8174: Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words"](https://www.rfc-editor.org/info/bcp14)
243+
244+
[^protocol-networks]: [Zcash Protocol Specification, Version 2024.5.1. Section 3.12: Mainnet and Testnet](protocol/protocol.pdf#networks)
245+
246+
[^bip-0032]: [BIP 32: Hierarchical Deterministic Wallets](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)
247+
248+
[^bip-0032-master-key-generation]: [BIP 32: Hierarchical Deterministic Wallets](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#master-key-generation)
249+
250+
[^bip-0032-key-identifiers]: [BIP 32: Hierarchical Deterministic Wallets](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#key-identifiers)
251+
252+
[^bip-0039]: [BIP 39: Mnemonic code for generating deterministic keys](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki)
253+
254+
[^bip-0045]: [BIP 45: Structure for Deterministic P2SH Multisignature Wallets](https://github.com/bitcoin/bips/blob/master/bip-0045.mediawiki)
255+
256+
[^bip-0048]: [BIP 48: Multi-Script Hierarchy for Multi-Sig Wallets](https://github.com/bitcoin/bips/blob/master/bip-0048.mediawiki)
257+
258+
[^bip-0067]: [BIP 67: Deterministic Pay-to-script-hash multi-signature addresses through public key sorting](https://github.com/bitcoin/bips/blob/master/bip-0067.mediawiki)
259+
260+
[^bip-0087]: [BIP 87: Hierarchy for Deterministic Multisig Wallets](https://github.com/bitcoin/bips/blob/master/bip-0087.mediawiki)
261+
262+
[^bip-0380]: [BIP 380: Output Script Descriptors General Operation](https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki)
263+
264+
[^bip-0381]: [BIP 381: Non-Segwit Output Script Descriptors](https://github.com/bitcoin/bips/blob/master/bip-0381.mediawiki)
265+
266+
[^bip-0383]: [BIP 383: Multisig Output Script Descriptors](https://github.com/bitcoin/bips/blob/master/bip-0383.mediawiki)
267+
268+
[^bip-0388]: [BIP 388: Wallet Policies for Descriptor Wallets](https://github.com/bitcoin/bips/blob/master/bip-0388.mediawiki)
269+
270+
[^bip-0388-key-information-vector]: [BIP 388: Wallet Policies for Descriptor Wallets. Key information vector](https://github.com/bitcoin/bips/blob/master/bip-0388.mediawiki#key-information-vector)
271+
272+
[^bip-0388-descriptor-derivation]: [BIP 388: Wallet Policies for Descriptor Wallets. Descriptor derivation](https://github.com/bitcoin/bips/blob/master/bip-0388.mediawiki#descriptor-derivation)
273+
274+
[^bip-0389]: [BIP 389: Multipath Descriptor Key Expressions](https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki)
275+
276+
[^slip-0044]: [SLIP-0044: Registered coin types for BIP-0044](https://github.com/satoshilabs/slips/blob/master/slip-0044.md)
277+
278+
[^zip-1016]: [ZIP 1016: Community and Coinholder Funding Model](zip-1016.md)

zips/zip-0316.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -479,8 +479,8 @@ $\mathtt{addr}$ field:
479479
$\mathsf{dk}\,||\,\mathsf{I2LEOSP}_{256}(\mathsf{ivk}).$
480480

481481
* There is no defined way to represent a Viewing Key for a Transparent
482-
P2SH Address in a UFVK or UIVK (because P2SH Addresses cannot be
483-
diversified in an unlinkable way). The Typecode $\mathtt{0x01}$
482+
P2SH Address in a UFVK or UIVK (because P2SH Addresses cannot, in general,
483+
be diversified in an unlinkable way). The Typecode $\mathtt{0x01}$
484484
MUST NOT be included in a UFVK or UIVK by Producers, and MUST be
485485
treated as unrecognised by Consumers.
486486

0 commit comments

Comments
 (0)