0342 - Final - Standards - Jan. 19, 2020 (6 years, 6 months ago)
19
2020
BIP: 342
Layer: Consensus (soft fork)
Title: Validation of Taproot Scripts
Author: Pieter Wuille <[email protected]>
Jonas Nick <[email protected]>
Anthony Towns <[email protected]>
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP 342
Status: Final
Type: Standards Track
Created: 2020-01-19
License: BSD-3-Clause
Post-History: 2019-05-06: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-May/016914.html [bitcoin-dev] Taproot proposal
Requires: 340, 341
This document specifies the semantics of the initial scripting system under BIP 341 .
This document is licensed under the 3-clause BSD license.
BIP 341 proposes improvements to just the script structure, but some of its goals are incompatible with the semantics of certain opcodes within the scripting language itself. While it is possible to deal with these in separate optional improvements, their impact is not guaranteed unless they are addressed simultaneously with BIP 341 itself.
Specifically, the goal is making Schnorr signatures , batch validation , and signature hash improvements available to spends that use the script system as well.
In order to achieve these goals, signature opcodes
OP_CHECKSIG
and
OP_CHECKSIGVERIFY
are modified
to verify Schnorr signatures as specified in
BIP 340
and to use a signature message algorithm based on the common message
calculation in
BIP 341
. The tapscript signature message also
simplifies
OP_CODESEPARATOR
handling and makes it more
efficient.
The inefficient
OP_CHECKMULTISIG
and
OP_CHECKMULTISIGVERIFY
opcodes are disabled. Instead, a new
opcode
OP_CHECKSIGADD
is introduced to allow creating the
same multisignature policies in a batch-verifiable way. Tapscript uses a
new, simpler signature opcode limit fixing complicated interactions with
transaction weight. Furthermore, a potential malleability vector is
eliminated by requiring MINIMALIF.
Tapscript can be upgraded through soft forks by defining unknown key
types, for example to add new
hash_types
or signature
algorithms. Additionally, the new tapscript
OP_SUCCESS
opcodes allow introducing new opcodes more cleanly than through
OP_NOP
.
The rules below only apply when validating a transaction input for which all of the conditions below are true:
Validation of such inputs must be equivalent to performing the following steps in the specified order.
OP_SUCCESS80
, ...,
OP_SUCCESS254
, and
collectively known as
OP_SUCCESSx
OP_SUCCESSx
OP_SUCCESSx
is a mechanism to upgrade the Script system.
Using an
OP_SUCCESSx
before its meaning is defined by a
softfork is insecure and leads to fund loss. The inclusion of
OP_SUCCESSx
in a script will pass it unconditionally. It
precedes any script execution rules to avoid the difficulties in
specifying various edge cases, for example:
OP_SUCCESSx
in
a script with an input stack larger than 1000 elements,
OP_SUCCESSx
after too many signature opcodes, or even
scripts with conditionals lacking
OP_ENDIF
. The mere
existence of an
OP_SUCCESSx
anywhere in the script will
guarantee a pass for all such cases.
OP_SUCCESSx
are
similar to the
OP_RETURN
in very early bitcoin versions
(v0.1 up to and including v0.3.5). The original
OP_RETURN
terminates script execution immediately, and return pass or fail based
on the top stack element at the moment of termination. This was one of a
major design flaws in the original bitcoin protocol as it permitted
unconditional third party theft by placing an
OP_RETURN
in
scriptSig
. This is not a concern in the present proposal
since it is not possible for a third party to inject an
OP_SUCCESSx
to the validation process, as the
OP_SUCCESSx
is part of the script (and thus committed to by
the taproot output), implying the consent of the coin owner.
OP_SUCCESSx
can be used for a variety of upgrade
possibilities:
OP_SUCCESSx
could be turned into a functional opcode
through a softfork. Unlike
OP_NOPx
-derived opcodes which
only have read-only access to the stack,
OP_SUCCESSx
may
also write to the stack. Any rule changes to an
OP_SUCCESSx
-containing script may only turn a valid script
into an invalid one, and this is always achievable with softforks.
OP_SUCCESSx
precedes size check of initial stack
and push opcodes, an
OP_SUCCESSx
-derived opcode requiring
stack elements bigger than 520 bytes may uplift the limit in a
softfork.
OP_SUCCESSx
may also redefine the behavior of existing
opcodes so they could work together with the new opcode. For example, if
an
OP_SUCCESSx
-derived opcode works with 64-bit integers,
it may also allow the existing arithmetic opcodes in the
same
script
to do the same.
OP_SUCCESSx
even causes potentially
unparseable scripts to pass, it can be used to introduce multi-byte
opcodes, or even a completely new scripting language when prefixed with
a specific
OP_SUCCESSx
opcode.
.
OP_SUCCESSx
.
CastToBool()
, fail.
The execution rules for tapscript are based on those for P2WSH
according to BIP 141, including the
OP_CHECKLOCKTIMEVERIFY
and
OP_CHECKSEQUENCEVERIFY
opcodes defined in
BIP 65
and
BIP
112
, but with the following modifications:
OP_CHECKMULTISIG
and
OP_CHECKMULTISIGVERIFY
1
. The disabled opcodes
behave in the same way as
OP_RETURN
, by failing and
terminating the script immediately when executed, and being ignored when
found in unexecuted branch of the script.
OP_IF
and
OP_NOTIF
opcodes must be either exactly 0 (the empty
vector) or exactly 1 (the one-byte vector with value 1)
2
.
OP_SUCCESSx
, and make the script
unconditionally valid.
OP_CHECKSIG
and
OP_CHECKSIGVERIFY
are modified to operate on Schnorr public
keys and signatures (see
BIP 340
) instead of ECDSA, and a new opcode
OP_CHECKSIGADD
is added.
0xba
) is named as
OP_CHECKSIGADD
.
3
Alternatives
to
CHECKMULTISIG
There are multiple ways of
implementing a threshold
k
-of-
n
policy using Taproot
and Tapscript:
OP_CHECKSIGADD
-based
script
A
CHECKMULTISIG
script
m <pubkey_1> ... <pubkey_n> n CHECKMULTISIG
with witness
0 <signature_1> ... <signature_m>
can be rewritten as script
<pubkey_1> CHECKSIG <pubkey_2> CHECKSIGADD ... <pubkey_n> CHECKSIGADD m NUMEQUAL
with witness
<w_n> ... <w_1>
. Every witness
element
w_i
is either a signature corresponding to
pubkey_i
or an empty vector. A similar
CHECKMULTISIGVERIFY
script can be translated to BIP 342 by
replacing
NUMEQUAL
with
NUMEQUALVERIFY
. This
approach has very similar characteristics to the existing
OP_CHECKMULTISIG
-based scripts.
<pubkey_1> CHECKSIGVERIFY ... <pubkey_(n-1)> CHECKSIGVERIFY <pubkey_n> CHECKSIG
.
This may be preferable for privacy reasons over the previous approach,
as it only exposes the participating public keys, but it is only more
cost effective for small values of
k
(1-of-
n
for any
n
, 2-of-
n
for
n ≥ 6
, 3-of-
n
for
n ≥ 9
, ...). Furthermore, the signatures here commit to the
branch used, which means signers need to be aware of which other signers
will be participating, or produce signatures for each of the tree
leaves.
The following rules apply to
OP_CHECKSIG
,
OP_CHECKSIGVERIFY
, and
OP_CHECKSIGADD
.
OP_CHECKSIGVERIFY
and
OP_CHECKSIG
, the
public key (top element) and a signature (second to top element) are
popped from the stack.
OP_CHECKSIGADD
, the public key (top element), a
CScriptNum
n
(second to top element), and a
signature (third to top element) are popped from the stack.
n
is larger than 4 bytes, the script MUST fail and
terminate immediately.
OP_CHECKSIGVERIFY
, the script MUST fail and
terminate immediately.
OP_CHECKSIG
, an empty vector is pushed onto the
stack, and execution continues with the next opcode.
OP_CHECKSIGADD
, a
CScriptNum
with
value
n
is pushed onto the stack, and execution continues
with the next opcode.
OP_CHECKSIGVERIFY
, execution continues without any
further changes to the stack.
OP_CHECKSIG
, a 1-byte value
0x01
is
pushed onto the stack.
OP_CHECKSIGADD
, a
CScriptNum
with
value of
n + 1
is pushed onto the stack.
We define the tapscript message extension ext to BIP 341 Common Signature Message , indicated by ext_flag = 1 :
OP_CODESEPARATOR
before the currently executed signature
opcode, with the value in little endian (or
0xffffffff
if none
executed). The first opcode in a script has a position of 0. A
multi-byte push opcode is counted as one opcode, regardless of the size
of data being pushed. Opcodes in parsed but unexecuted branches count
towards this value as well.
To validate a signature sig with public key p :
In summary, the semantics of signature validation is identical to BIP 340, except the following:
OP_CODESEPARATOR
.
OP_CODESEPARATOR
.
6
In addition to changing the semantics of a number of opcodes, there are also some changes to the resource limitations:
CompactSize
prefix). Executing a signature opcode
(
OP_CHECKSIG
,
OP_CHECKSIGVERIFY
, or
OP_CHECKSIGADD
) with a non-empty signature decrements the
budget by 50. If that brings the budget below zero, the script fails
immediately. Signature opcodes with unknown public key type and
non-empty signature are also counted.
9
10
11
.
This proposal is deployed identically to Taproot ( BIP 341 ).
The Taproot ( BIP 341 ) test vectors also contain examples for Tapscript execution.
This document is the result of many discussions and contains contributions by a number of people. The authors wish to thank all those who provided valuable feedback and reviews, including the participants of the structured reviews .
OP_CHECKMULTISIG
and
OP_CHECKMULTISIGVERIFY
disabled, and not turned into
OP_SUCCESSx?
This is a precaution to make sure people who
accidentally keep using
OP_CHECKMULTISIG
in Tapscript
notice a problem immediately. It also avoids the complication of script
disassemblers needing to become context-dependent.
↩︎
OP_CHECKSIGADD
This opcode is
added to compensate for the loss of
OP_CHECKMULTISIG
-like
opcodes, which are incompatible with batch verification.
OP_CHECKSIGADD
is functionally equivalent to
OP_ROT OP_SWAP OP_CHECKSIG OP_ADD
, but only takes 1 byte.
All
CScriptNum
-related behaviours of
OP_ADD
are also applicable to
OP_CHECKSIGADD
.
↩︎
SIGHASH
modes can
be added, as well as
NOINPUT-tagged
public keys
and a public key constant which is replaced by the
taproot internal key for signature validation.
↩︎
OP_CODESEPARATOR
?
This allows
continuing to use
OP_CODESEPARATOR
to sign the executed
path of the script. Because the
codeseparator_position
is
the last input to the hash, the SHA256 midstate can be efficiently
cached for multiple
OP_CODESEPARATOR
s in a single script.
In contrast, the BIP 143 handling of
OP_CODESEPARATOR
is to
commit to the executed script only from the last executed
OP_CODESEPARATOR
onwards which requires unnecessary
rehashing of the script. It should be noted that the one known
OP_CODESEPARATOR
use case of saving a second public key
push in a script by sharing the first one between two code branches can
be most likely expressed even cheaper by moving each branch into a
separate taproot leaf.
↩︎
scriptCode
directly
included in the signature hash (only indirectly through a precomputable
tapleaf hash), the CPU time spent on a signature check is no longer
proportional to the size of the script being executed.
↩︎
OP_IF
,
OP_NOTIF
,
OP_ELSE
, and
OP_ENDIF
as suggested
here
and implemented
here
, the only
other instance can be avoided as well.
↩︎
SIGHASH_ALL
) signature pairs
with
33 + 65
weight units each (which includes a 1 weight unit
CompactSize
tag). This is also the case if public keys are
reused in the script because a signature's weight alone is 65 or 66
weight units. However, the limit increases the fees of abnormal scripts
with duplicate signatures (and public keys) by requiring additional
weight. The weight per sigop factor 50 corresponds to the ratio of BIP
141 block limits: 4 mega weight units divided by 80,000 sigops. The
"free" signature opcode permitted by the limit exists to account for the
weight of the non-witness parts of the transaction input.
↩︎
OP_ROLL
(taking the 1000 stack element limit into
account). That said, the construction is very flexible, and allows
adding new signature opcodes like
CHECKSIGFROMSTACK
to
count towards the limit through a soft fork. Even if in the future new
opcodes are introduced which change normal script cost there is no need
to stuff the witness with meaningless data. Instead, the taproot annex
can be used to add weight to the witness without increasing the actual
witness size.
↩︎