mirror of
https://github.com/seigler/dash-docs
synced 2025-07-27 09:46:12 +00:00
Dev Docs Correction: CHECKMULTISIG Requires Sigs In Same Order As PubKeys
As reported by @gsalgado (thanks!), the docs incorrectly state that all sigs are compared against all pubkeys. This commit provides a corrected description, additional details, and references in other parts of the text where we mention multisig. (Fixes #622)
This commit is contained in:
parent
82dcaf218a
commit
1ec71148da
3 changed files with 74 additions and 11 deletions
|
@ -94,7 +94,10 @@ OP_0 [A's signature] [B's or C's signature] [serialized redeem script]
|
|||
|
||||
(Op codes to push the signatures and redeem script onto the stack are
|
||||
not shown. `OP_0` is a workaround for an off-by-one error in the original
|
||||
implementation which must be preserved for compatibility.)
|
||||
implementation which must be preserved for compatibility. Note that
|
||||
the signature script must provide signatures in the same order as the
|
||||
corresponding public keys appear in the redeem script. See the description in
|
||||
[`OP_CHECKMULTISIG`][op_checkmultisig] for details.)
|
||||
|
||||
When the transaction is broadcast to the network, each peer checks the
|
||||
signature script against the P2SH output Charlie previously paid,
|
||||
|
|
|
@ -360,11 +360,16 @@ consumes one more value from the stack than indicated by *m*, so the
|
|||
list of secp256k1 signatures in the signature script must be prefaced with an extra value
|
||||
(`OP_0`) which will be consumed but not used.
|
||||
|
||||
The signature script must provide signatures in the same order as the
|
||||
corresponding public keys appear in the pubkey script or redeem
|
||||
script. See the desciption in [`OP_CHECKMULTISIG`][op_checkmultisig]
|
||||
for details.
|
||||
|
||||
{% endautocrossref %}
|
||||
|
||||
~~~
|
||||
Pubkey script: <m> <pubkey> [pubkey] [pubkey...] <n> OP_CHECKMULTISIG
|
||||
Signature script: OP_0 <sig> [sig] [sig...]
|
||||
Pubkey script: <m> <A pubkey> [B pubkey] [C pubkey...] <n> OP_CHECKMULTISIG
|
||||
Signature script: OP_0 <A sig> [B sig] [C sig...]
|
||||
~~~
|
||||
|
||||
{% autocrossref %}
|
||||
|
@ -375,8 +380,8 @@ Although it’s not a separate transaction type, this is a P2SH multisig with 2-
|
|||
|
||||
~~~
|
||||
Pubkey script: OP_HASH160 <Hash160(redeemScript)> OP_EQUAL
|
||||
Redeem script: <OP_2> <pubkey> <pubkey> <pubkey> <OP_3> OP_CHECKMULTISIG
|
||||
Signature script: OP_0 <sig> <sig> <redeemScript>
|
||||
Redeem script: <OP_2> <A pubkey> <B pubkey> <C pubkey> <OP_3> OP_CHECKMULTISIG
|
||||
Signature script: OP_0 <A sig> <C sig> <redeemScript>
|
||||
~~~
|
||||
|
||||
{% autocrossref %}
|
||||
|
|
|
@ -37,14 +37,25 @@ The op codes used in the pubkey scripts of standard transactions are:
|
|||
* [`OP_CHECKMULTISIG`][op_checkmultisig]{:#term-op-checkmultisig}{:.term} consumes the value (n) at the top of the stack,
|
||||
consumes that many of the next stack levels (public keys), consumes
|
||||
the value (m) now at the top of the stack, and consumes that many of
|
||||
the next values (signatures) plus one extra value. Then it compares
|
||||
each of public keys against each of the signatures looking for ECDSA
|
||||
matches; if n of the public keys match signatures, it pushes true onto the stack.
|
||||
Otherwise, it pushes false.
|
||||
the next values (signatures) plus one extra value.
|
||||
|
||||
The "one extra value" it consumes is the result of an off-by-one
|
||||
error in the Bitcoin Core implementation. This value is not used, so
|
||||
signature scripts prefix the secp256k1 signatures with a single OP_0 (0x00).
|
||||
signature scripts prefix the list of secp256k1 signatures with a
|
||||
single OP_0 (0x00).
|
||||
|
||||
`OP_CHECKMULTISIG` compares the first signature against each public
|
||||
key until it finds an ECDSA match. Starting with the subsequent
|
||||
public key, it compares the second signature against each remaining
|
||||
public key until it finds an ECDSA match. The process is repeated
|
||||
until all signatures have been checked or not enough public keys
|
||||
remain to produce a successful result.
|
||||
|
||||
Because public keys are not checked again if they fail any signature
|
||||
comparison, signatures must be placed in the signature script using
|
||||
the same order as their corresponding public keys were placed in
|
||||
the pubkey script or redeem script. See the `OP_CHECKMULTISIG` warning
|
||||
below for more details.
|
||||
|
||||
* [`OP_RETURN`][op_return]{:#term-op-return}{:.term} terminates the script in failure when executed.
|
||||
|
||||
|
@ -52,7 +63,8 @@ A complete list of OP codes can be found on the Bitcoin Wiki [Script
|
|||
Page][wiki script], with an authoritative list in the `opcodetype` enum
|
||||
of the Bitcoin Core [script header file][core script.h]
|
||||
|
||||
Note: Signature scripts are not signed, so anyone can modify them. This
|
||||

|
||||
**Signature script modification warning:** Signature scripts are not signed, so anyone can modify them. This
|
||||
means signature scripts should only contain data and data-pushing op
|
||||
codes which can't be modified without causing the pubkey script to fail.
|
||||
Placing non-data-pushing op codes in the signature script currently
|
||||
|
@ -60,6 +72,49 @@ makes a transaction non-standard, and future consensus rules may forbid
|
|||
such transactions altogether. (Non-data-pushing op codes are already
|
||||
forbidden in signature scripts when spending a P2SH pubkey script.)
|
||||
|
||||

|
||||
**`OP_CHECKMULTISIG` warning:** The multisig verification process
|
||||
described above requires that signatures in the signature script be
|
||||
provided in the same order as their corresponding public keys in
|
||||
the pubkey script or redeem script. For example, the following
|
||||
combined signature and pubkey script will produce the stack and
|
||||
comparisons shown:
|
||||
|
||||
{% highlight text %}
|
||||
OP_0 <A sig> <B sig> OP_2 <A pubkey> <B pubkey> <C pubkey> OP_3
|
||||
|
||||
Sig Stack Pubkey Stack (Actually a single stack)
|
||||
--------- ------------
|
||||
B sig C pubkey
|
||||
A sig B pubkey
|
||||
OP_0 A pubkey
|
||||
|
||||
1. B sig compared to C pubkey (no match)
|
||||
2. B sig compared to B pubkey (match #1)
|
||||
3. A sig compared to A pubkey (match #2)
|
||||
|
||||
Success: two matches found
|
||||
{% endhighlight %}
|
||||
|
||||
But reversing the order of the signatures with everything else the same
|
||||
will fail, as shown below:
|
||||
|
||||
{% highlight text %}
|
||||
OP_0 <B sig> <A sig> OP_2 <A pubkey> <B pubkey> <C pubkey> OP_3
|
||||
|
||||
Sig Stack Pubkey Stack (Actually a single stack)
|
||||
--------- ------------
|
||||
A sig C pubkey
|
||||
B sig B pubkey
|
||||
OP_0 A pubkey
|
||||
|
||||
1. A sig compared to C pubkey (no match)
|
||||
2. A sig compared to B pubkey (no match)
|
||||
|
||||
Failure, aborted: two signature matches required but none found so
|
||||
far, and there's only one pubkey remaining
|
||||
{% endhighlight %}
|
||||
|
||||
{% endautocrossref %}
|
||||
|
||||
#### Address Conversion
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue