<p>The conditions for spending a coin (UTxO) are expressed using a small <a href="https://en.bitcoin.it/wiki/Script" rel="nofollow noreferrer">script</a>. In order to be able to recover your coins, you need to back up both:</p>
<ul>
<li>The script template</li>
<li>The private key(s) corresponding to the public key(s) used in the script</li>
</ul>
<p>You need the script template because the script expressing the spending conditions is part of the coin itself. And the wallet needs to be able to locate which coins you own from the set of all existing ones (the &quot;UTxO set&quot;).</p>
<p>This is true for any type of script (single-sigs, multisigs, or even more complex constructions). But it is often <strong>implicitly</strong> assumed backups with no corresponding script template are for a single-sig. The wallet would therefore reconstruct a single-sig script template from your private key.</p>
<p>It is however not possible to reconstruct any other script than a single-sig only from a private key. Hence the recommendation to back up other public keys involved in the multisig along with your own private key. This is simply a manner of backing up the script template to be able to locate your coins. (It's however a very incomplete manner.)</p>
<p>Backing up the public keys as a way to reconstruct the script template is suboptimal because it's leaving out a lot of information:</p>
<ul>
<li>What's the script type? Is it using a bare script, a P2SH, a P2WSH, a P2TR?</li>
<li>What's the construction used? Is it using <code>CHECKMULTISIG</code>, a list of <code>CHECKSIG</code>s? A list of <code>CHECKSIGADD</code>s?</li>
<li>If using Taproot, in what leaf is the multisig? Is it spanning multiple leaves?</li>
</ul>
<p>Modern Bitcoin wallets nowadays use <a href="https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki" rel="nofollow noreferrer">Output Script Descriptors</a> as a way of describing <strong>all</strong> the information needed to reconstruct a script template. I recommend using it to backup your multisig (or anything else) instead of relying on implicit information for something so critical.</p>

CC BY-SA 4.0
2023-09-17T00:06:13.570Z
I don't fully follow. 1. Would the Output Script Descriptor contain the derivation paths or would it be kept separate? 2. In the case of a multisig from 2 hardware wallets & 1 seed signer would there be a single OSD for the multisg wallet? Or 3 individual OSDs, one for each multisig constituent?
Runeaway3
CC BY-SA 4.0
2023-09-17T10:41:51.123Z
1. It's part of the descriptor. 2. Yes. It looks something like `multi(2,xpub1/*,xpub2/*,xpub3/*)` (not technically correct but simplified so you get the gist).
Antoine Poinsot
CC BY-SA 4.0
2023-09-17T16:28:54.607Z
And how would this be generated? If I self create the multisig via sparrow, is there an automated mechanism to generate this OSD?
Runeaway3
CC BY-SA 4.0
2023-09-18T00:23:05.723Z
You would generate one (or your wallet would) before receiving funds, and derive addresses from it. I'm not sure but i think you can access your descriptor from within Sparrow.
Antoine Poinsot
CC BY-SA 4.0
2023-09-16T15:55:24.290Z
2023-10-19T16:40:34.013Z
2023-10-19T16:40:34.013Z
Antoine Poinsot
<p>The common practice in Bitcoin is to use <a href="https://en.bitcoin.it/wiki/Pay_to_script_hash" rel="nofollow noreferrer">&quot;pay-to-script-hash&quot;</a> for multisig. In fact that is the only way to receive money in a standard &quot;address&quot; for your multisig wallet (there are variants in non-SegWit world, SegWit v0 and Taproot).</p>
<p>Pay-to-script-hash means the sender doesn't know where the money is being sent to. All it knows is that it is sending it to a &quot;hash&quot; of the actual script that specifies the spending conditions -- in this case a multisig script that looks like <code>2 &lt;key1&gt; &lt;key2&gt; &lt;key3&gt; 3 OP_CHECKMULTISIG</code>.</p>
<p>To spend <em>any</em> pay-to-script-hash UTXO you have to provide the actual script first -- which the Bitcoin verification process will hash and check. And then (in the same transaction) you provide the signatures that will fulfill the script.</p>
<p>For example, <a href="https://mempool.space/tx/1b03f23996b77c6e32f6f01c94748dc0131d6274ac48d5704a619481575f0858" rel="nofollow noreferrer">this transaction</a> is sending 1631068 satoshis to a 2-of-3 multisig address, but you can't know that just by looking at it. All you can see is that it is paying to the hash <code>a64224765fa40b1bb04a4e8f82d29ca580e2022e20750078b5c3bd610b9015c9</code>.</p>
<p>However, since it was spent in <a href="https://mempool.space/tx/f44aa16a7052d2f31d675437a181e894b7569cad13e063b8a032d8922bd18d77" rel="nofollow noreferrer">this transaction</a> you can see the script that it used. It is the last element in the witness stack -- <code>522102b4608d0bba8f2f5665648462819d4a0fe97a8012d386d88ebb4e1ddc93fba5af2102db19c6f47c04ac128a8d9015a75dc350e5291849f999d267598d019dcdf5cbae21030994d7f93c0fb81eeeae14cabe0dbc8a547a9770aca304f4633eaab743fbc06a53ae</code>, which translates (using <code>bitcoin-cli decodescript</code> or <a href="https://github.com/stevenroose/hal" rel="nofollow noreferrer"><code>hal script decode</code></a>) into:</p>
<pre><code>OP_PUSHNUM_2 
OP_PUSHBYTES_33 02b4608d0bba8f2f5665648462819d4a0fe97a8012d386d88ebb4e1ddc93fba5af 
OP_PUSHBYTES_33 02db19c6f47c04ac128a8d9015a75dc350e5291849f999d267598d019dcdf5cbae 
OP_PUSHBYTES_33 030994d7f93c0fb81eeeae14cabe0dbc8a547a9770aca304f4633eaab743fbc06a 
OP_PUSHNUM_3
OP_CHECKMULTISIG
</code></pre>
<p>Finally, if you check the sha256 hash of the (byte-encoded) script above you'll see that it matches the script hash from the previous transaction.</p>
<pre class="lang-python prettyprint-override"><code>&gt;&gt;&gt; b = bytes.fromhex('522102b4608d0bba8f2f5665648462819d4a0fe97a8012d386d88ebb4e1ddc93fba5af2102db19c6f47c04ac128a8d9015a75dc350e5291849f999d267598d019dcdf5cbae21030994d7f93c0fb81eeeae14cabe0dbc8a547a9770aca304f4633eaab743fbc06a53ae')
&gt;&gt;&gt; hashlib.sha256(b).hexdigest()
'a64224765fa40b1bb04a4e8f82d29ca580e2022e20750078b5c3bd610b9015c9'
</code></pre>

CC BY-SA 4.0
2023-10-19T16:57:29.083Z
You could perhaps explicitly answer the question of the asker by mentioning that you can only provide the actual script if you know all public keys. E.g. you could append “If you don’t know all public keys, you cannot reconstitute the actual script.” to the third paragraph.
Murch
CC BY-SA 4.0
2023-09-16T16:40:38.137Z
2023-10-19T16:48:14.743Z
2023-10-19T16:48:14.743Z
fiatjaf
<p>Trying to conceptually understand why I must store the public keys of the n hardware wallets in an x of n multisig set up? Only x of the <strong>seed phrases/private keys</strong> are needed to reconstitute/recover the multisig wallet, but why do I need all n public keys?<br />
My understanding is that to <em>send</em> btc I only need x private keys (aka the x wallets on hand), to receive I just need the resultant multisig public key stored, but to recover I need x private keys <strong>and</strong> n public keys? Why is this?</p>

<multi-signature><wallet-recovery><hardware-wallet>
Why are n public keys needed for reconstitution of an x of n multisig?
Runeaway3
# Why are n public keys needed for reconstitution of an x of n multisig?

(Asked by: username_0 on 2023-09-16)

Trying to conceptually understand why I must store the public keys of the n hardware wallets in an x of n multisig set up? Only x of the **seed phrases/private keys** are needed to reconstitute/recover the multisig wallet, but why do I need all n public keys?  
My understanding is that to *send* btc I only need x private keys (aka the x wallets on hand), to receive I just need the resultant multisig public key stored, but to recover I need x private keys **and** n public keys? Why is this?

**Tags:** multi-signature, wallet-recovery, hardware-wallet


---

## 2 answers

### Answer by username_1 on 2023-09-16. Score: 5

The conditions for spending a coin (UTxO) are expressed using a small [script](https://en.bitcoin.it/wiki/Script). In order to be able to recover your coins, you need to back up both:

* The script template
* The private key(s) corresponding to the public key(s) used in the script

You need the script template because the script expressing the spending conditions is part of the coin itself. And the wallet needs to be able to locate which coins you own from the set of all existing ones (the "UTxO set").

This is true for any type of script (single-sigs, multisigs, or even more complex constructions). But it is often **implicitly** assumed backups with no corresponding script template are for a single-sig. The wallet would therefore reconstruct a single-sig script template from your private key.

It is however not possible to reconstruct any other script than a single-sig only from a private key. Hence the recommendation to back up other public keys involved in the multisig along with your own private key. This is simply a manner of backing up the script template to be able to locate your coins. (It's however a very incomplete manner.)

Backing up the public keys as a way to reconstruct the script template is suboptimal because it's leaving out a lot of information:

* What's the script type? Is it using a bare script, a P2SH, a P2WSH, a P2TR?
* What's the construction used? Is it using `CHECKMULTISIG`, a list of `CHECKSIG`s? A list of `CHECKSIGADD`s?
* If using Taproot, in what leaf is the multisig? Is it spanning multiple leaves?

Modern Bitcoin wallets nowadays use [Output Script Descriptors](https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki) as a way of describing **all** the information needed to reconstruct a script template. I recommend using it to backup your multisig (or anything else) instead of relying on implicit information for something so critical.

> **Comments:**
> **username_0**: I don't fully follow. 1. Would the Output Script Descriptor contain the derivation paths or would it be kept separate? 2. In the case of a multisig from 2 hardware wallets & 1 seed signer would there be a single OSD for the multisg wallet? Or 3 individual OSDs, one for each multisig constituent?  
> **username_1**: 1. It's part of the descriptor. 2. Yes. It looks something like `multi(2,xpub1/*,xpub2/*,xpub3/*)` (not technically correct but simplified so you get the gist).  
> **username_0**: And how would this be generated? If I self create the multisig via sparrow, is there an automated mechanism to generate this OSD?  
> **username_1**: You would generate one (or your wallet would) before receiving funds, and derive addresses from it. I'm not sure but i think you can access your descriptor from within Sparrow.  

---

### Answer by username_2 on 2023-09-16. Score: 3

The common practice in Bitcoin is to use ["pay-to-script-hash"](https://en.bitcoin.it/wiki/Pay_to_script_hash) for multisig. In fact that is the only way to receive money in a standard "address" for your multisig wallet (there are variants in non-SegWit world, SegWit v0 and Taproot).

Pay-to-script-hash means the sender doesn't know where the money is being sent to. All it knows is that it is sending it to a "hash" of the actual script that specifies the spending conditions -- in this case a multisig script that looks like `2 <key1> <key2> <key3> 3 OP_CHECKMULTISIG`.

To spend *any* pay-to-script-hash UTXO you have to provide the actual script first -- which the Bitcoin verification process will hash and check. And then (in the same transaction) you provide the signatures that will fulfill the script.

For example, [this transaction](https://mempool.space/tx/1b03f23996b77c6e32f6f01c94748dc0131d6274ac48d5704a619481575f0858) is sending 1631068 satoshis to a 2-of-3 multisig address, but you can't know that just by looking at it. All you can see is that it is paying to the hash `a64224765fa40b1bb04a4e8f82d29ca580e2022e20750078b5c3bd610b9015c9`.

However, since it was spent in [this transaction](https://mempool.space/tx/f44aa16a7052d2f31d675437a181e894b7569cad13e063b8a032d8922bd18d77) you can see the script that it used. It is the last element in the witness stack -- `522102b4608d0bba8f2f5665648462819d4a0fe97a8012d386d88ebb4e1ddc93fba5af2102db19c6f47c04ac128a8d9015a75dc350e5291849f999d267598d019dcdf5cbae21030994d7f93c0fb81eeeae14cabe0dbc8a547a9770aca304f4633eaab743fbc06a53ae`, which translates (using `bitcoin-cli decodescript` or [`hal script decode`](https://github.com/stevenroose/hal)) into:

```
OP_PUSHNUM_2 
OP_PUSHBYTES_33 02b4608d0bba8f2f5665648462819d4a0fe97a8012d386d88ebb4e1ddc93fba5af 
OP_PUSHBYTES_33 02db19c6f47c04ac128a8d9015a75dc350e5291849f999d267598d019dcdf5cbae 
OP_PUSHBYTES_33 030994d7f93c0fb81eeeae14cabe0dbc8a547a9770aca304f4633eaab743fbc06a 
OP_PUSHNUM_3
OP_CHECKMULTISIG

```

Finally, if you check the sha256 hash of the (byte-encoded) script above you'll see that it matches the script hash from the previous transaction.

```python
>>> b = bytes.fromhex('522102b4608d0bba8f2f5665648462819d4a0fe97a8012d386d88ebb4e1ddc93fba5af2102db19c6f47c04ac128a8d9015a75dc350e5291849f999d267598d019dcdf5cbae21030994d7f93c0fb81eeeae14cabe0dbc8a547a9770aca304f4633eaab743fbc06a53ae')
>>> hashlib.sha256(b).hexdigest()
'a64224765fa40b1bb04a4e8f82d29ca580e2022e20750078b5c3bd610b9015c9'

```

> **Comments:**
> **username_3**: You could perhaps explicitly answer the question of the asker by mentioning that you can only provide the actual script if you know all public keys. E.g. you could append “If you don’t know all public keys, you cannot reconstitute the actual script.” to the third paragraph.  

---

