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
|
(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
|
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
|
When the transaction is broadcast to the network, each peer checks the
|
||||||
signature script against the P2SH output Charlie previously paid,
|
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
|
list of secp256k1 signatures in the signature script must be prefaced with an extra value
|
||||||
(`OP_0`) which will be consumed but not used.
|
(`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 %}
|
{% endautocrossref %}
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
Pubkey script: <m> <pubkey> [pubkey] [pubkey...] <n> OP_CHECKMULTISIG
|
Pubkey script: <m> <A pubkey> [B pubkey] [C pubkey...] <n> OP_CHECKMULTISIG
|
||||||
Signature script: OP_0 <sig> [sig] [sig...]
|
Signature script: OP_0 <A sig> [B sig] [C sig...]
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
{% autocrossref %}
|
{% 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
|
Pubkey script: OP_HASH160 <Hash160(redeemScript)> OP_EQUAL
|
||||||
Redeem script: <OP_2> <pubkey> <pubkey> <pubkey> <OP_3> OP_CHECKMULTISIG
|
Redeem script: <OP_2> <A pubkey> <B pubkey> <C pubkey> <OP_3> OP_CHECKMULTISIG
|
||||||
Signature script: OP_0 <sig> <sig> <redeemScript>
|
Signature script: OP_0 <A sig> <C sig> <redeemScript>
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
{% autocrossref %}
|
{% 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,
|
* [`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
|
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 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
|
the next values (signatures) plus one extra value.
|
||||||
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 "one extra value" it consumes is the result of an off-by-one
|
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
|
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.
|
* [`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
|
Page][wiki script], with an authoritative list in the `opcodetype` enum
|
||||||
of the Bitcoin Core [script header file][core script.h]
|
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
|
means signature scripts should only contain data and data-pushing op
|
||||||
codes which can't be modified without causing the pubkey script to fail.
|
codes which can't be modified without causing the pubkey script to fail.
|
||||||
Placing non-data-pushing op codes in the signature script currently
|
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
|
such transactions altogether. (Non-data-pushing op codes are already
|
||||||
forbidden in signature scripts when spending a P2SH pubkey script.)
|
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 %}
|
{% endautocrossref %}
|
||||||
|
|
||||||
#### Address Conversion
|
#### Address Conversion
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue