From 1ec71148daa7ebd6580a451d410d76ecf7726655 Mon Sep 17 00:00:00 2001 From: "David A. Harding" Date: Tue, 28 Oct 2014 21:33:26 -0400 Subject: [PATCH] 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) --- _includes/guide_contracts.md | 5 ++- _includes/guide_transactions.md | 13 +++++-- _includes/ref_transactions.md | 67 ++++++++++++++++++++++++++++++--- 3 files changed, 74 insertions(+), 11 deletions(-) diff --git a/_includes/guide_contracts.md b/_includes/guide_contracts.md index 19424fe0..c5e68f76 100644 --- a/_includes/guide_contracts.md +++ b/_includes/guide_contracts.md @@ -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, diff --git a/_includes/guide_transactions.md b/_includes/guide_transactions.md index ef40936e..d667704b 100644 --- a/_includes/guide_transactions.md +++ b/_includes/guide_transactions.md @@ -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: [pubkey] [pubkey...] OP_CHECKMULTISIG -Signature script: OP_0 [sig] [sig...] +Pubkey script: [B pubkey] [C pubkey...] OP_CHECKMULTISIG +Signature script: OP_0 [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 OP_EQUAL -Redeem script: OP_CHECKMULTISIG -Signature script: OP_0 +Redeem script: OP_CHECKMULTISIG +Signature script: OP_0 ~~~ {% autocrossref %} diff --git a/_includes/ref_transactions.md b/_includes/ref_transactions.md index 1260ed70..d90742e4 100644 --- a/_includes/ref_transactions.md +++ b/_includes/ref_transactions.md @@ -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 +![Warning icon](/img/icon_warning.svg) +**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.) +![Warning icon](/img/icon_warning.svg) +**`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 OP_2 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 OP_2 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