update documentation for multisig quorum constraints
Motivation
Consensus declares 520 as the maximum number of bytes pushable to the stack, but this alone does not define the multisig quorum constraints.
https://github.com/bitcoin/bitcoin/blob/ae024137bda9fe189f4e7ccf26dbaffd44cbbeb6/src/script/script.h#L28
Consider the following constant in standard node policy https://github.com/bitcoin/bitcoin/blob/3eaa0a3b663782bb1bd874ea881b21649f1db767/src/policy/policy.h#L54-L56
static constexpr unsigned int MAX_STANDARD_SCRIPTSIG_SIZE{1650};
For 2-of-3 the spending scripts are structured as follows, and placed in the scriptSig for P2SH and in the witness items for P2WSH.
OP_0
OP_PUSH72 <ecdsa_signature> OP_PUSH72 <ecdsa_signature>
OP_PUSHDATA1 105
<OP_2 OP_PUSH33 <pubkey> OP_PUSH33 <pubkey> OP_PUSH33 <pubkey> OP_3 OP_CHECKMULTISIG>
We can generalize this to M of N
OP_0
(OP_PUSH72 * <ecdsa_signature>)*M
OP_PUSHDATA2 <size>
OP_M (OP_PUSH33 <pubkey>)*N OP_N OP_CHECKMULTISIG
Let's assume for a moment that we let M=N, so we can solve for the maximum number of keys we can have in a multisig script. (Let's use M=N=K)
NOTE: When N > 8 we have 1+(34*8) + 2 = 276 which is more than 256 bytes we can specify in OP_PUSHDATA1, so we need to use OP_PUSHDATA2.
| Operation | Byte Count |
|---|---|
OP_0 |
1 |
OP_PUSH72 * <ecdsa_signature>)*K |
73*K |
OP_PUSHDATA2 <size> |
3 |
OP_M (OP_PUSH33 <pubkey>)*N OP_N OP_CHECKMULTISIG |
3 + 34*K |
With a max of 1650 bytes for P2SH
1 + 73 \cdot K + 3 + 3 + 34 \cdot K = 7 + 107 \cdot K
\implies K = floor\>\frac{1650-7}{107} = 15
∴ The theoretical maximum number of keys in a P2SH quorum with M=N is 15. Derived not from script element size, but from the maximum size of the scriptSig in policy.
Thanks for the quick feedback @scgbckbone! I appreciate you entertaining the amendment to the doc and would like to refine it for accuracy as you suggest.
The optech calculator has been an excellent reference for my own understanding in transaction construction especially around the consensus limitations for script. https://bitcoinops.org/en/tools/calc-size/#output
It helps distinguish between the hashed redeem script that's placed in the scriptPubKey of outputs, which is generally fixed at 23 bytes (160 bits from HASH160), and the scriptSig of inputs. I'm suggesting the latter is the true limiting factor for the number of signers in P2SH.
It's not relevant for native segwit since the spending scripts are serialized in the witness data. For P2SH the entire redeem script is exposed in the scriptSig, and each script element does not exceed 520 bytes. The largest is the 72 byte ECDSA signatures. If using bare multisig in the scriptPubKey, the 520 byte limit is also not exceeded.
With respect to the parenthetical comment, it appears the MAX_SIGNERS constant is indeed enforced for both P2SH and P2WSH? I'm looking at shared/multisig.py which imports the constant from external/ckcc-protocol/ckcc/constants.py. I might need to dive deeper into the implementation to understand.
I've included a note about the 520 byte limit rather than just deleting it entirely, let me know if I've misunderstood anything about the segwit limits or should rephrase. Thank you again for the time!
EDIT: here is an additional reference comment in core (which ironically may be inaccurate in its reference to the MAX_SCRIPT_ELEMENT_SIZE)
https://github.com/bitcoin/bitcoin/blob/ae024137bda9fe189f4e7ccf26dbaffd44cbbeb6/src/policy/policy.cpp#L122-L129
EDIT 2: if accepted I can create a complimentary pull request to ckcc-protocol to update this comment
https://github.com/Coldcard/ckcc-protocol/blob/master/ckcc/constants.py#L47, along the lines of
-# - 520 byte redeem script limit <= 15*34 bytes per pubkey == 510 bytes
+# - 1650 byte scriptSig limit >= 1+73*M+3+3+34*M=1612, where M is 15 pubkeys
With respect to the parenthetical comment, it appears the MAX_SIGNERS constant is indeed enforced for both P2SH and P2WSH? I'm looking at shared/multisig.py which imports the constant from external/ckcc-protocol/ckcc/constants.py. I might need to dive deeper into the implementation to understand.
that is correct - we enforce max N=15 limit for segwit too (for no good reason but nobody asked for N>15 yet)